选择与列表中的所有项匹配的行

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)

  • 但是,这不适用于通配符,因为在这种情况下无法建立显式计数。 (2认同)

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为每个CarNamePassedTest一个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)


Sal*_*n A 9

您想要执行关系除法,这是 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)