use*_*351 34 sql t-sql sql-server relational-division
假设我有两个表:
cars - 汽车清单
carname | modelnumber | ...
Run Code Online (Sandbox Code Playgroud)
passedtest - 包含汽车通过的每项测试:
id | carname | testtype | date | ...
1 | carA | A | 2000 |
2 | carB | C | 2000 |
3 | carC | D | 2001 |
4 | carA | C | 2002 |
Run Code Online (Sandbox Code Playgroud)
现在,我如何从passedtest通过所有测试(A,B,C,D)的表格中选择一辆汽车?
我尝试了这个IN声明,但它也匹配通过一次测试的汽车.我正在寻找一个语句来匹配所有行中列表中的所有值.
Mar*_*zek 40
这个怎么样?
SELECT carname
FROM PassedTest
GROUP BY carname
HAVING COUNT(DISTINCT testtype) = 4
Run Code Online (Sandbox Code Playgroud)
您还可以将其用作从cars表中获取信息的内部语句:
SELECT *
FROM cars
WHERE carname IN (
SELECT carname
FROM PassedTest
GROUP BY carname
HAVING COUNT(DISTINCT testtype) = 4
)
Run Code Online (Sandbox Code Playgroud)
Joh*_*Woo 34
这种类型的问题被称为Relational Division.
SELECT a.*
FROM Cars a
INNER JOIN
(
SELECT CarName
FROM PassedTest
WHERE testType IN ('A', 'B', 'C', 'D')
GROUP BY CarName
HAVING COUNT(*) = 4
) b ON a.CarName = b.CarName
Run Code Online (Sandbox Code Playgroud)
如果UNIQUE约束被不强制执行TestType为每个CarName表PassedTest一个DISTINCT需要在关键字COUNT(),因此只能算唯一值.
SELECT a.*
FROM Cars a
INNER JOIN
(
SELECT CarName
FROM PassedTest
WHERE testType IN ('A', 'B', 'C', 'D')
GROUP BY CarName
HAVING COUNT(DISTINCT TestType) = 4
) b ON a.CarName = b.CarName
Run Code Online (Sandbox Code Playgroud)
但如果您只对此感兴趣,CARNAME那么您不需要加入表格.在桌子上查询PassedTest将满足您的需求.
SELECT CarName
FROM PassedTest
WHERE testType IN ('A', 'B', 'C', 'D')
GROUP BY CarName
HAVING COUNT(*) = 4
Run Code Online (Sandbox Code Playgroud)
您想要执行关系除法,这是 SQL 中未实现的操作。这是一个示例,其中我们有一个product-supplier表和一个required-products表:
CREATE TABLE product_supplier (
product_id int NOT NULL,
supplier_id int NOT NULL,
UNIQUE (product_id, supplier_id)
);
INSERT INTO product_supplier (product_id, supplier_id) VALUES
(1, 1),
(2, 1),
(3, 1),
(1, 2),
(2, 2),
(3, 2),
(4, 2),
(2, 3),
(3, 3),
(4, 3);
CREATE TABLE reqd (
product_id int NOT NULL,
UNIQUE (product_id)
);
INSERT INTO reqd (product_id) VALUES
(1),
(2),
(3);
Run Code Online (Sandbox Code Playgroud)
...我们希望找到所有供应商提供所有必需的产品,也许还有其他产品。上例中的结果是供应商 1 和 2。
最直接的解决方案是这样的:
SELECT product_supplier.supplier_id
FROM product_supplier
LEFT JOIN reqd ON product_supplier.product_id = reqd.product_id
GROUP BY product_supplier.supplier_id
HAVING COUNT(reqd.product_id) = (SELECT COUNT(*) FROM reqd);
Run Code Online (Sandbox Code Playgroud)
CREATE TABLE product_supplier (
product_id int NOT NULL,
supplier_id int NOT NULL,
UNIQUE (product_id, supplier_id)
);
INSERT INTO product_supplier (product_id, supplier_id) VALUES
(1, 1),
(2, 1),
(3, 1),
(1, 2),
(2, 2),
(3, 2),
(4, 2),
(2, 3),
(3, 3),
(4, 3);
CREATE TABLE reqd (
product_id int NOT NULL,
UNIQUE (product_id)
);
INSERT INTO reqd (product_id) VALUES
(1),
(2),
(3);
Run Code Online (Sandbox Code Playgroud)
如果我们想找到提供所有必需产品而没有其他产品的所有供应商(精确划分/无余数),则在上述条件中再添加一个条件:
SELECT product_supplier.supplier_id
FROM product_supplier
LEFT JOIN reqd ON product_supplier.product_id = reqd.product_id
GROUP BY product_supplier.supplier_id
HAVING COUNT(reqd.product_id) = (SELECT COUNT(*) FROM reqd)
AND COUNT(product_supplier.product_id) = (SELECT COUNT(*) FROM reqd);
Run Code Online (Sandbox Code Playgroud)
SELECT product_supplier.supplier_id
FROM product_supplier
LEFT JOIN reqd ON product_supplier.product_id = reqd.product_id
GROUP BY product_supplier.supplier_id
HAVING COUNT(reqd.product_id) = (SELECT COUNT(*) FROM reqd);
Run Code Online (Sandbox Code Playgroud)
另一种解决方案是重新表述这个问题:选择供应商提供的产品中不存在所需产品的供应商。嗯:
SELECT DISTINCT supplier_id
FROM product_supplier AS ps1
WHERE NOT EXISTS (
SELECT *
FROM reqd
WHERE NOT EXISTS (
SELECT *
FROM product_supplier AS ps2
WHERE ps1.supplier_id = ps2.supplier_id AND ps2.product_id = reqd.product_id
)
);
Run Code Online (Sandbox Code Playgroud)
+-------------+
| supplier_id |
+-------------+
| 1 |
| 2 |
+-------------+
Run Code Online (Sandbox Code Playgroud)