[英]mySQL join three tables and search on several keywords found in one table
I'm trying to limit the size of my database by avoiding multiple records containing the same words and therefore I have build two tables used to relate keyword to rows in other tables. 我试图通过避免包含相同单词的多个记录来限制数据库的大小,因此我建立了两个表,用于将关键字与其他表中的行相关联。
As an example, we use the follwing search input: "find my" 例如,我们使用以下搜索输入:“找到我”
What is wish go get as a hit, is the product_name from product_id = 106. Could I just search on the product name? 希望得到什么,这是product_id = 106中的product_name。我可以仅搜索产品名称吗? No, because the product can be associated with other keywords, that are not part of the product_name.
否,因为产品可以与其他关键字(不属于product_name的一部分)相关联。
TABLE: ec_products 表格:ec_products
product_id | product_name | is_deleted
---------------------------------------------
106 | some product | 0
TABLE: ec_keywords_index 表格:ec_keywords_index
word_id | keyword
---------------------------------------------
55 | find
61 | my
77 | product
TABLE: ec_keyword_relations 表格:ec_keyword_relations
word_id | application_id | related_id
------------------------------------------------
55 | 1 | 106
61 | 1 | 106
77 | 1 | 106
So, what I want now when I enter "find my" into my search input is: 因此,当我在搜索输入中输入“ find my”时,我现在想要的是:
Here is what I've tried so far (and I know that I am very far from a working solution at the time being): 这是到目前为止我已经尝试过的方法(并且我知道我暂时还没有一个可行的解决方案):
$searchInput = 'find my';
$keywords = explode(' ', $searchInput);
$keyword_count = count($keywords);
$n = 1;
$query = '';
foreach($keywords as $keyword) {
if ($n !== $keyword_count) {
$query_ext = ' AND ';
} else {
$query_ext = '';
}
$query .= "(ec_keywords_index.keyword LIKE '%$keyword%')" . $query_ext;
++$n;
}
$query = "
SELECT
ec_products.product_name
FROM
ec_products
LEFT JOIN ec_search_word_relations
ON ec_keyword_relations.related_id = ec_products.product_id
LEFT JOIN ec_keywords_index
ON ec_keywords_index.word_id = ec_keyword_relations.word_id
WHERE
($query)
AND
ec_products.is_deleted = '0'
AND
ec_keyword_relations.application_id = '1'
GROUP BY
ec_products.product_id
ORDER BY
ec_products.product_name ASC
LIMIT
100";
$stmt = $mysqli->prepare($query);
$stmt->execute();
$stmt->store_result();
$stmt->bind_result($name);
while ($stmt->fetch()) {
echo $name;
}
UPDATE: 更新:
After some fiddling around, I have come up with this solution which works just as expected. 经过一番摆弄之后,我想出了可以按预期工作的解决方案。 Is it (in terms) of performance a good or a bad solution?
(就性能而言)是好的还是坏的解决方案?
$searchInput = 'find my';
$keywords = explode(' ', $searchInput);
$keyword_count = count($keywords);
$n = 1;
$where_query = '';
$having_query = '';
foreach($keywords as $keyword) {
if ($n != $keyword_count) {
$w_query_ext = ' OR ';
$h_query_ext = ' AND ';
} else {
$w_query_ext = '';
$h_query_ext = '';
}
$where_query .= "ec_keywords_index.keyword LIKE '%" . $keyword . "%'" . $w_query_ext;
$having_query .= "related_keywords LIKE '%" . $keyword . "%'" . $h_query_ext;
++$n;
}
$query = "
SELECT
ec_products.product_name,
GROUP_CONCAT(' ', ec_keywords_index.keyword) AS 'related_keywords'
FROM
ec_products,
ec_keywords_index
LEFT JOIN
ec_keyword_relations
ON ec_keyword_relations.word_id = ec_keywords_index.word_id
WHERE ($where_query)
AND ec_products.product_id = ec_keyword_relations.related_id
AND ec_keyword_relations.application_id = '1'
AND ec_products.is_deleted = '0'
GROUP BY
ec_products.product_name
HAVING
($having_query)
LIMIT
100";
$stmt = $mysqli->prepare($query);
$stmt->execute();
$stmt->store_result();
$stmt->bind_result($name);
while ($stmt->fetch()) {
echo $name;
}
The above example outputs a query like this: 上面的示例输出如下查询:
SELECT
ec_products.product_name,
GROUP_CONCAT(' ', ec_keywords_index.keyword) AS 'related_keywords'
FROM
ec_products,
ec_keywords_index
LEFT JOIN
ec_keyword_relations
ON ec_keyword_relations.word_id = ec_keywords_index.word_id
WHERE (ec_keywords_index.keyword LIKE '%find%' OR ec_keywords_index.keyword LIKE '%my%')
AND ec_products.product_id = ec_keyword_relations.related_id
AND ec_keyword_relations.application_id = '1'
AND ec_products.is_deleted = '0'
GROUP BY
ec_products.product_name
HAVING
(related_keywords LIKE '%find%' AND related_keywords LIKE '%my%')
LIMIT
100
I'm using GROUP_CONCAT to create a column containing all the keywords related to the products, then my WHERE clause is used to ONLY select the keywords that are actually found in my search string... Then the HAVING clause is used to search in column build using GROUP_CONCAT. 我正在使用GROUP_CONCAT创建一个包含与产品相关的所有关键字的列,然后使用我的WHERE子句仅选择在搜索字符串中实际找到的关键字...然后使用HAVING子句在该列中进行搜索使用GROUP_CONCAT构建。
OWN ANSWER WITH EXAMPLE: 拥有示例的答案:
After some fiddling around, I have come up with this solution which works just as expected. 经过一番摆弄之后,我想出了可以按预期工作的解决方案。 I don't know if it is best practice, but it works like a charm.
我不知道这是否是最佳做法,但它就像一个魅力。
$searchInput = 'find my';
$keywords = explode(' ', $searchInput);
$keyword_count = count($keywords);
$n = 1;
$where_query = '';
$having_query = '';
foreach($keywords as $keyword) {
if ($n != $keyword_count) {
$w_query_ext = ' OR ';
$h_query_ext = ' AND ';
} else {
$w_query_ext = '';
$h_query_ext = '';
}
$where_query .= "ec_keywords_index.keyword LIKE '%" . $keyword . "%'" . $w_query_ext;
$having_query .= "related_keywords LIKE '%" . $keyword . "%'" . $h_query_ext;
++$n;
}
$query = "
SELECT
ec_products.product_name,
GROUP_CONCAT(' ', ec_keywords_index.keyword) AS 'related_keywords'
FROM
ec_products,
ec_keywords_index
LEFT JOIN
ec_keyword_relations
ON ec_keyword_relations.word_id = ec_keywords_index.word_id
WHERE ($where_query)
AND ec_products.product_id = ec_keyword_relations.related_id
AND ec_keyword_relations.application_id = '1'
AND ec_products.is_deleted = '0'
GROUP BY
ec_products.product_name
HAVING
($having_query)
LIMIT
100";
$stmt = $mysqli->prepare($query);
$stmt->execute();
$stmt->store_result();
$stmt->bind_result($name);
while ($stmt->fetch()) {
echo $name;
}
The above example outputs a query like this: 上面的示例输出如下查询:
SELECT
ec_products.product_name,
GROUP_CONCAT(' ', ec_keywords_index.keyword) AS 'related_keywords'
FROM
ec_products,
ec_keywords_index
LEFT JOIN
ec_keyword_relations
ON ec_keyword_relations.word_id = ec_keywords_index.word_id
WHERE (ec_keywords_index.keyword LIKE '%find%' OR ec_keywords_index.keyword LIKE '%my%')
AND ec_products.product_id = ec_keyword_relations.related_id
AND ec_keyword_relations.application_id = '1'
AND ec_products.is_deleted = '0'
GROUP BY
ec_products.product_name
HAVING
(related_keywords LIKE '%find%' AND related_keywords LIKE '%my%')
LIMIT
100
I'm using GROUP_CONCAT to create a column containing all the keywords related to the products, then my WHERE clause is used to ONLY select the keywords that are actually found in my search string... Then the HAVING clause is used to search in column build using GROUP_CONCAT. 我正在使用GROUP_CONCAT创建一个包含与产品相关的所有关键字的列,然后使用我的WHERE子句仅选择在搜索字符串中实际找到的关键字...然后使用HAVING子句在该列中进行搜索使用GROUP_CONCAT构建。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.