web-dev-qa-db-ja.com

リスト内のすべてのアイテムに一致する行のグループを選択します

2つのテーブルがあるとします。

cars –車のリスト

carname | modelnumber | ...

passedtest –車が合格したすべてのテストが含まれます。

id | carname | testtype | date | ...
1  | carA    | A        | 2000 |
2  | carB    | C        | 2000 |
3  | carC    | D        | 2001 |
4  | carA    | C        | 2002 |

さて、すべてのテスト(A、B、C、D)に合格したpassedtestテーブルから車を選択するにはどうすればよいですか?

INステートメントを試しましたが、1つのテストにも合格した車にも一致します。すべての行にわたるリスト内のall値に一致するステートメントを探しています。

33
user1229351

これはどう?

SELECT carname
FROM PassedTest
GROUP BY carname
HAVING COUNT(DISTINCT testtype) = 4

carsテーブルから情報を取得するための内部ステートメントとして使用することもできます。

SELECT *
FROM cars
WHERE carname IN (
    SELECT carname
    FROM PassedTest
    GROUP BY carname
    HAVING COUNT(DISTINCT testtype) = 4
)
40
MarcinJuraszek

このタイプの問題は_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
_

UNIQUE制約がテーブルのTestTypeごとにCarNameに適用されなかった場合PassedTest a 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
_

ただし、CARNAMEのみに関心がある場合は、テーブルを結合する必要はありません。テーブルPassedTestのクエリは、ニーズに合っています。

_SELECT  CarName
FROM    PassedTest 
WHERE   testType IN ('A', 'B', 'C', 'D')
GROUP   BY CarName
HAVING  COUNT(*) = 4
_
32
John Woo

リレーショナル除算、つまり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);

...そして、必要なすべての製品とおそらく他の製品を提供するすべてのサプライヤーを探しています。上記の例の結果は、サプライヤ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);
+-------------+
| supplier_id |
+-------------+
|           1 |
|           2 |
+-------------+

そして、必要なすべての製品を提供し、他の製品を提供しないすべてのサプライヤー(正確な部門/余剰なし)を検索する場合は、上記にもう1つの条件を追加します。

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);
+-------------+
| supplier_id |
+-------------+
|           1 |
+-------------+

別の解決策は、問題を言い換えることです。必要な製品が存在せず、サプライヤーによって提供された製品に存在しないサプライヤーを選択します。うーん

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
    )
);
+-------------+
| supplier_id |
+-------------+
|           1 |
|           2 |
+-------------+
3
Salman A