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値に一致するステートメントを探しています。
これはどう?
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
)
このタイプの問題は_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
_
リレーショナル除算、つまり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 |
+-------------+