简体   繁体   中英

Selecting title, description and keywords from MySQL database using PHP

I am coding a tiny search engine for my practice. I want to add up search functionality in it. I am trying to select all rows of questions table upon matching title, description and keywords.

I created the following 3 tables:

questions(id(PK), title, description)

keywords(id(PK), label);

questions_keywords(id(PK), question_id(FK), keyword_id(FK));

So far my SQL query looks like this:

SELECT q.* FROM question_keywords qk 
JOIN keywords k ON qk.keyword_id=k.id 
JOIN questions q ON qk.question_id=q.id 
WHERE q.description LIKE '%javascript%' 
OR 
k.keyword_label LIKE '%java%'

In this query, i am selecting all the rows from questions table containing the substring java or javascript

Am I doing it right or there is a better way to do it??

Thanks in advance.

AS others mentioned I would add distinct. I would also reorder the tables. Functionally I don't think it matters it just bugged me... ha ha

SELECT DISTINCT
    q.*
FROM
    questions AS q
JOIN
    question_keywords AS qk ON q.id = qk.question_id
JOIN
    keywords AS k ON qk.keyword_id = k.id
WHERE
    q.description LIKE '%javascript%'
OR
    k.label LIKE '%java%';

As you can see in this DBfiddle

https://www.db-fiddle.com/f/pcVqcMm1yUoU6NdSHitCVr/2

The reason you get duplicates is basically called a Cartesian product

https://en.wikipedia.org/wiki/Cartesian_product

In simple terms is just a consequence of having a "Many to Many" relationship.

If you see in the fiddle I intentionally created this situation by what I added to the Bridge ( or Junction ) table question_keywords in the last 2 Inserts

INSERT INTO question_keywords (question_id,keyword_id)VALUES(4,1);
INSERT INTO question_keywords (question_id,keyword_id)VALUES(4,2);

The duplicate row, is simply because there are 2 entries for this table with the matching value of 4 for question_id . So these are only Duplicates in the sense that we are only selecting the fields form the questions table. If we included fields from the keywords table. Then one row would have a keyword or Java #1 while the other would have Javascript #2 as the keyword.

Hope that helps explain it.

A few other things to note:

  1. You have a syntax error in the query you posted k.keyword_label LIKE '%java%' should be k.label LIKE '%java%' according to your table definition in the question.

  2. Typically the Junction table should be a combination of both tables it joins ( which you almost did ) but the pluralization is wrong question_keywords should be questions_keywords it's a small thing but it could cause confusion when writing queries.

  3. There is really not a need for a separate primary key for the Junction table.

If you notice how I created the table in the fiddle.

CREATE TABLE question_keywords( 
    question_id INT(10) UNSIGNED NOT NULL,
    keyword_id INT(10) UNSIGNED NOT NULL,
    PRIMARY KEY(question_id,keyword_id)
);

The primary key is a compound of the 2 foreign keys. This has the added benefit of preventing real duplicate rows from being made. For example if you tried this

INSERT INTO question_keywords (question_id,keyword_id)VALUES(4,1);
INSERT INTO question_keywords (question_id,keyword_id)VALUES(4,1);

With the setup I have it would be impossible to create the duplicate. You can still have a separate primary key (surrogate key), but you should create a compound unique index on those 2 keys in place of it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM