返回所有相关 WHERE 匹配的行
Returning row where all related WHEREs match
我需要 return 匹配多对多关系上所有 WHERE 语句的结果。解释一下:
我有一个这样的table结构。
CREATE TABLE `product` (
`product_id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`product_id`));
CREATE TABLE `product_has_tag` (
`product_id` INT UNSIGNED NOT NULL,
`tag_id` INT UNSIGNED NOT NULL
);
CREATE TABLE `tag` (
`tag_id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`value` VARCHAR(30) NULL,
PRIMARY KEY (`tag_id`));
现在我遇到这样的情况:
Product: {
[product_id:1],
[product_id:2],
[product_id:3]};
Tags: {
[tag_id:1, value:'XX'],
[tag_id:2, value:'YY']}
ProductHasTag: {
[product_id:1, tag_id:1],
[product_id:1, tag_id:2],
[product_id:2, tag_id:1],
[product_id:3, tag_id:2]}
基本上,只有一种产品有两个标签,其余只有一个。现在我需要一个 SQL 搜索条件,它将 return 仅包含两个标签的产品。像
SELECT * FROM `product`
LEFT JOIN product_has_tag USING(product_id)
LEFT JOIN tag USING(tag_id)
WHERE value LIKE '%X%' AND value LIKE '%Y%'
这显然不起作用,因为搜索值不在一个标签中,而是在两个标签中。
任何帮助表示赞赏。
您需要像处理两个不同的列一样处理这两个不同的标签。这需要一些花哨的连接工作。
此查询为您提供符合第一个条件的产品。
SELECT p.*, t1.value tag1
FROM product p
JOIN product_has_tag pt1 ON p.product_id = pt1.product_id
JOIN tag t1 ON pt1.tag_id = t1.tag_id AND t1.value LIKE '%X%'
您可以向此查询添加一些内容以获得您想要的两个标签。
SELECT p.*, t1.value tag1, t2.value tag2
FROM product p
JOIN product_has_tag pt1 ON p.product_id = pt1.product_id
JOIN tag t1 ON pt1.tag_id = t1.tag_id AND t1.value LIKE '%X%'
JOIN product_has_tag pt2 ON p.product_id = pt2.product_id
JOIN tag t2 ON pt2.tag_id = t2.tag_id AND t2.value LIKE '%Y%'
JOIN 项目将导致此查询将您的产品行与两个匹配的标签隔离开来。
您在此查询中的 value LIKE '%match%'
模式将导致性能不佳。如果您可以使用 value LIKE 'match%'
或 value = 'match'
性能将能够利用 value
列上的索引。
您可以汇总匹配的标签,并且只有 return 有 2 个匹配的结果。
SELECT * FROM product
LEFT JOIN product_has_tag USING(product_id)
LEFT JOIN tag USING(tag_id)
WHERE value LIKE '%X%' OR value LIKE '%Y%'
GROUP BY product_id HAVING COUNT(DISTINCT tag_id) = 2
您只需要将 WHERE
更改为 HAVING
并使用 SUM CASE WHEN
SELECT `product`.`product_id` -- *
FROM `product`
LEFT JOIN product_has_tag
USING(product_id)
LEFT JOIN tag
USING(tag_id)
GROUP BY `product`.`product_id`
HAVING SUM(CASE WHEN `value` LIKE '%X%' THEN 1 END) > 0
AND SUM(CASE WHEN `value` LIKE '%Y%' THEN 1 END) > 0
我需要 return 匹配多对多关系上所有 WHERE 语句的结果。解释一下:
我有一个这样的table结构。
CREATE TABLE `product` (
`product_id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`product_id`));
CREATE TABLE `product_has_tag` (
`product_id` INT UNSIGNED NOT NULL,
`tag_id` INT UNSIGNED NOT NULL
);
CREATE TABLE `tag` (
`tag_id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`value` VARCHAR(30) NULL,
PRIMARY KEY (`tag_id`));
现在我遇到这样的情况:
Product: {
[product_id:1],
[product_id:2],
[product_id:3]};
Tags: {
[tag_id:1, value:'XX'],
[tag_id:2, value:'YY']}
ProductHasTag: {
[product_id:1, tag_id:1],
[product_id:1, tag_id:2],
[product_id:2, tag_id:1],
[product_id:3, tag_id:2]}
基本上,只有一种产品有两个标签,其余只有一个。现在我需要一个 SQL 搜索条件,它将 return 仅包含两个标签的产品。像
SELECT * FROM `product`
LEFT JOIN product_has_tag USING(product_id)
LEFT JOIN tag USING(tag_id)
WHERE value LIKE '%X%' AND value LIKE '%Y%'
这显然不起作用,因为搜索值不在一个标签中,而是在两个标签中。 任何帮助表示赞赏。
您需要像处理两个不同的列一样处理这两个不同的标签。这需要一些花哨的连接工作。
此查询为您提供符合第一个条件的产品。
SELECT p.*, t1.value tag1
FROM product p
JOIN product_has_tag pt1 ON p.product_id = pt1.product_id
JOIN tag t1 ON pt1.tag_id = t1.tag_id AND t1.value LIKE '%X%'
您可以向此查询添加一些内容以获得您想要的两个标签。
SELECT p.*, t1.value tag1, t2.value tag2
FROM product p
JOIN product_has_tag pt1 ON p.product_id = pt1.product_id
JOIN tag t1 ON pt1.tag_id = t1.tag_id AND t1.value LIKE '%X%'
JOIN product_has_tag pt2 ON p.product_id = pt2.product_id
JOIN tag t2 ON pt2.tag_id = t2.tag_id AND t2.value LIKE '%Y%'
JOIN 项目将导致此查询将您的产品行与两个匹配的标签隔离开来。
您在此查询中的 value LIKE '%match%'
模式将导致性能不佳。如果您可以使用 value LIKE 'match%'
或 value = 'match'
性能将能够利用 value
列上的索引。
您可以汇总匹配的标签,并且只有 return 有 2 个匹配的结果。
SELECT * FROM product
LEFT JOIN product_has_tag USING(product_id)
LEFT JOIN tag USING(tag_id)
WHERE value LIKE '%X%' OR value LIKE '%Y%'
GROUP BY product_id HAVING COUNT(DISTINCT tag_id) = 2
您只需要将 WHERE
更改为 HAVING
并使用 SUM CASE WHEN
SELECT `product`.`product_id` -- *
FROM `product`
LEFT JOIN product_has_tag
USING(product_id)
LEFT JOIN tag
USING(tag_id)
GROUP BY `product`.`product_id`
HAVING SUM(CASE WHEN `value` LIKE '%X%' THEN 1 END) > 0
AND SUM(CASE WHEN `value` LIKE '%Y%' THEN 1 END) > 0