Предполагая, что у меня есть следующая таблица базы данных:
ID | Name | Type | Value|
--- --------- ---------- ------
1 | First | A | 10 |
2 | First | B | 20 |
3 | First | C | 30 |
4 | First | D | 40 |
5 | Second | A | 10 |
6 | Second | B | 20 |
и возвращается предыдущий запрос:
ID | Name | Type | Value|
--- --------- ---------- ------
1 | Third | A | 10 |
2 | Third | B | 20 |
3 | Third | C | 30 |
Мой вопрос: каков наилучший способ запросить первую таблицу и получить все записи, имеющие хотя бы весь тип, возвращаемый в предыдущем запросе?
В приведенном выше примере имя "Третий" имеет типы AB C. Используя их как список, я хотел бы получить только "первые" записи (так как "First" имеет ABCD), но не "Second" (так как "Second" имеет только AB - отсутствует C).
Оператор IN соответствует eveything, и я хочу, чтобы запрос соответствовал по крайней мере всем элементам в моем "типе" списке. Список не обязательно поступает из SQL-запроса, но может быть предоставлен
EDIT: Я работаю с MySQL
Включены два варианта одного и того же запроса для любой базы данных.
SELECT main.*
FROM main
LEFT JOIN (
SELECT name, json_arrayagg(type) as type
FROM main
GROUP BY name
) AS main_agg USING(name)
WHERE EXISTS (
SELECT 1
FROM (
select json_arrayagg(type) as type
from query
group by name
) AS query_agg
WHERE JSON_CONTAINS(main_agg.type, query_agg.type)
)
WITH main_agg AS
(
SELECT name, array_agg(type) "type"
FROM main
GROUP BY name
)
SELECT main.*
FROM main
JOIN main_agg USING(name)
WHERE EXISTS (
SELECT 1
FROM (select array_agg(type) "type" from query group by name) query_agg
WHERE main_agg."type" @> query_agg."type"
)
@>
(содержит оператор) для сравнения с запросом(Работает для MySQL или PostgreSQL)
CREATE TABLE main
(ID int, Name varchar(6), Type varchar(1), Value int)
;
INSERT INTO main
(ID, Name, Type, Value)
VALUES
(1, 'First', 'A', 10),
(2, 'First', 'B', 20),
(3, 'First', 'C', 30),
(4, 'First', 'D', 40),
(5, 'Second', 'A', 10),
(6, 'Second', 'B', 20)
;
CREATE TABLE query
(ID int, Name varchar(5), Type varchar(1), Value int)
;
INSERT INTO query
(ID, Name, Type, Value)
VALUES
(1, 'Third', 'A', 10),
(2, 'Third', 'B', 20),
(3, 'Third', 'C', 30)
;
В стандартном SQL вы можете сделать это как join
и group by
помощью некоторой фильтрации. Далее предполагается, что type
уникален для каждого имени в каждой таблице:
with prevq as (
. . .
)
select t.name
from t join
prevq
on t.type = prevq.type
group by t.name
having count(*) = (select count(*) from prevq);
РЕДАКТИРОВАТЬ:
MySQL не поддерживает CTE (до 8.0). Это достаточно легко обойти:
select t.name
from t join
(<your query here>) prevq
on t.type = prevq.type
group by t.name
having count(*) = (select count(*) from (<your query here>) prevq);