0

Выбрать группу строк, которые соответствуют всем элементам списка

15

У меня есть две таблицы:

  1. cars – список автомобилей:
carname | modelnumber | ...
  1. passedtest – содержит информацию о каждом тесте, который прошел автомобиль:
id | carname | testtype | date | ...
1  | carA    | A        | 2000 |
2  | carB    | C        | 2000 |
3  | carC    | D        | 2001 |
4  | carA    | C        | 2002 |

Мне нужно выбрать автомобиль из таблицы passedtest, который прошел все тесты (A, B, C, D).

Я пробовал использовать оператор IN, но он также находит автомобили, которые проходят хотя бы один тест. Мне нужно составить запрос, который будет соответствовать всем значениям в списке по всем строкам.

Как правильно сформулировать такой запрос?

2 ответ(ов)

0

Ваш запрос выглядит вполне корректно. Вы используете подзапрос для выборки автомобилей, которые прошли 4 различных типа тестов.

Вот как он работает:

  1. Во вложенном запросе (SELECT carname FROM PassedTest GROUP BY carname HAVING COUNT(DISTINCT testtype) = 4) вы выбираете только те автомобили (carname), которые соответствуют условию, что количество уникальных типов тестов (testtype) равно 4.

  2. Затем во внешнем запросе (SELECT * FROM cars WHERE carname IN (...)) вы выбираете все записи из таблицы cars, где название автомобиля присутствует в списке автомобилей из подзапроса.

Это хороший подход, если вы хотите получить все детали о автомобилях, которые прошли определённые тесты. Убедитесь, что ваше условие HAVING подходит именно для вашей задачи – т.е. вам действительно нужно учитывать только автомобили, прошедшие 4 разных теста.

Если же вас интересует, например, только большее количество показателей или их отсутствие, возможно, вам стоит рассмотреть другие варианты фильтрации.

Если у вас есть дополнительные вопросы или уточнения по поводу структуры таблиц или данных, не стесняйтесь уточнять!

0

Вы хотите выполнить операцию деления в реляционных базах данных, которая не реализована в 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 |
+-------------+

Если мы хотим найти всех поставщиков, которые снабжают ВСЕ необходимые продукты и ничего лишнего (точное деление без остатка), то добавьте еще одно условие к вышеуказанному запросу:

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 |
+-------------+

Таким образом, вы можете использовать оба подхода в зависимости от ваших целей и предпочтений.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь