SQL 使用跨越多行的 AND 规则进行过滤
SQL filter with AND rule spanning multiple rows
我有一个 MySQL 数据库,类似于:
item table
| id | name |
item_category link table
| item_id | category_id |
category table
| id | name |
如果我想获取与多个类别之一相关的项目,我可以简单地执行以下操作:
SELECT item.*
FROM item
JOIN item_category ON item_category.item_id = item.id
LEFT JOIN category ON category.id = item_category.category_id
WHERE category.name in ("category_one", "category_two")
但是,如果我想获取与类别列表的 all 相关的项目,那么问题会变得有点复杂,因为从我的查询返回的行包含每个单一类别。我如何编写一个仅包含与 所有 类别相关的项目的查询?
我试过用这样的嵌套 select 编写查询:
SELECT item.*
FROM item
WHERE EXISTS (
SELECT item.id
FROM item_category ON item_category.item_id = item.id
LEFT JOIN category ON category.id = item_category.category_id
WHERE item_category.id = item.id
AND category.name = "category_one"
)
AND EXISTS (
SELECT item.id
FROM item_category ON item_category.item_id = item.id
LEFT JOIN category ON category.id = item_category.category_id
WHERE item_category.id = item.id
AND category.name = "category_two"
)
但是,即使在相关字段上有索引,这也是令人难以置信的低效。
感谢您对此问题的任何意见。
执行此操作的典型方法是 (1) 为每个必须匹配的值连接到 "category" 电缆一次,或 (2) 聚合您的第一个查询(按项目分组)并过滤其中 count(distinct category.name)
= 您的值列表中的项目数。
考虑以下...
DROP TABLE IF EXISTS category;
CREATE TABLE category
(id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
,name VARCHAR(12) NOT NULL UNIQUE
);
INSERT INTO category VALUES
(101,'animals'),
(102,'minerals'),
(103,'vegetables');
DROP TABLE IF EXISTS item_category;
CREATE TABLE item_category
(item_id INT NOT NULL
,category_id INT NOT NULL
,PRIMARY KEY(item_id,category_id)
);
INSERT INTO item_category VALUES
(1,101),
(1,102),
(1,103),
(2,102),
(3,101),
(3,103);
通过检查,我们可以看到只有项目 1 与所有类别相关联。
那么,我们如何 select 那些不是的项目?
SELECT DISTINCT ic.item_id
FROM item_category ic
JOIN category c ON c.id <> ic.category_id
LEFT
JOIN item_category x
ON x.item_id = ic.item_id
AND x.category_id = c.id
WHERE x.item_id IS NULL;
+---------+
| item_id |
+---------+
| 2 |
| 3 |
+---------+
属于所有类别的项目列表,是该集合的倒数。
我有一个 MySQL 数据库,类似于:
item table
| id | name |
item_category link table
| item_id | category_id |
category table
| id | name |
如果我想获取与多个类别之一相关的项目,我可以简单地执行以下操作:
SELECT item.*
FROM item
JOIN item_category ON item_category.item_id = item.id
LEFT JOIN category ON category.id = item_category.category_id
WHERE category.name in ("category_one", "category_two")
但是,如果我想获取与类别列表的 all 相关的项目,那么问题会变得有点复杂,因为从我的查询返回的行包含每个单一类别。我如何编写一个仅包含与 所有 类别相关的项目的查询?
我试过用这样的嵌套 select 编写查询:
SELECT item.*
FROM item
WHERE EXISTS (
SELECT item.id
FROM item_category ON item_category.item_id = item.id
LEFT JOIN category ON category.id = item_category.category_id
WHERE item_category.id = item.id
AND category.name = "category_one"
)
AND EXISTS (
SELECT item.id
FROM item_category ON item_category.item_id = item.id
LEFT JOIN category ON category.id = item_category.category_id
WHERE item_category.id = item.id
AND category.name = "category_two"
)
但是,即使在相关字段上有索引,这也是令人难以置信的低效。
感谢您对此问题的任何意见。
执行此操作的典型方法是 (1) 为每个必须匹配的值连接到 "category" 电缆一次,或 (2) 聚合您的第一个查询(按项目分组)并过滤其中 count(distinct category.name)
= 您的值列表中的项目数。
考虑以下...
DROP TABLE IF EXISTS category;
CREATE TABLE category
(id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
,name VARCHAR(12) NOT NULL UNIQUE
);
INSERT INTO category VALUES
(101,'animals'),
(102,'minerals'),
(103,'vegetables');
DROP TABLE IF EXISTS item_category;
CREATE TABLE item_category
(item_id INT NOT NULL
,category_id INT NOT NULL
,PRIMARY KEY(item_id,category_id)
);
INSERT INTO item_category VALUES
(1,101),
(1,102),
(1,103),
(2,102),
(3,101),
(3,103);
通过检查,我们可以看到只有项目 1 与所有类别相关联。
那么,我们如何 select 那些不是的项目?
SELECT DISTINCT ic.item_id
FROM item_category ic
JOIN category c ON c.id <> ic.category_id
LEFT
JOIN item_category x
ON x.item_id = ic.item_id
AND x.category_id = c.id
WHERE x.item_id IS NULL;
+---------+
| item_id |
+---------+
| 2 |
| 3 |
+---------+
属于所有类别的项目列表,是该集合的倒数。