У меня есть таблица, подобная этой
NAME FLAG
---------------------------
abc 1
abc 0
abc 2
def 1
def 2
xyz 0
xyz 0
xyz 1
efg 1
Мне нужен запрос, который перечисляет имя (group the result), флаг которого не включен 0 и включал результат 1.The, как показано ниже:
NAME FLAG
------------------
def 1
efg 1
Я пробовал запрос, но не тот же результат.
select * mytable where FLAG NOT IN (0) GROUP BY NAME;
Это самое простое решение, которое я могу придумать. Я считаю, что возможны более элегантные ответы.
SELECT *
FROM mytable
WHERE name NOT IN (SELECT name FROM mytable WHERE flag = 0)
AND flag = 1;
Мы можем использовать агрегацию. Хитрость заключается в том, чтобы запустить условие для каждой строки, а затем использовать функцию агрегата, чтобы выбрать чистый результат условия из всех строк...
SELECT t.name
FROM a_table_like_this t
GROUP BY t.name
HAVING MAX(t.flag=0) <> 1
AND MAX(t.flag=1) = 1
Выражения в предложении HAVING являются сокращением MySQL. Более эквивалентным стандартом ANSI будет:
SELECT t.name
FROM a_table_like_this t
GROUP BY t.name
HAVING MAX( CASE WHEN t.flag=0 THEN 1 ELSE 0 END) <> 1
AND MAX( CASE WHEN t.flag=1 THEN 1 ELSE 0 END) = 1
Чтобы лучше понять, что это делает, взгляните на то, как эти выражения оцениваются в каждой строке. Удалите предложение GROUP BY и переместите эти выражения в список SELECT...
SELECT t.name
, t.flag
, CASE WHEN t.flag=0 THEN 1 ELSE 0 END AS 'fl=0'
, CASE WHEN t.flag=1 THEN 1 ELSE 0 END AS 'fl=1'
FROM a_table_like_this t
ORDER
BY t.name
, t.flag
Мы получаем что-то вроде
name flag fl=0 fl=1
------ ---- ---- ----
abc 1 0 1
abc 0 1 0
abc 2 0 0
def 1 0 1
def 2 0 0
xyz 0 1 0
xyz 0 1 0
xyz 1 0 1
efg 1 0 1
Если мы теперь агрегируем эти строки по имени (GROUP BY name
), мы можем использовать агрегат MAX()
для выделения 1
(если она есть в группе, иначе мы вернем 0
).
И мы можем сделать условные тесты по результатам агрегатных функций в предложении HAVING
.
Таким образом вы можете использовать предложение NOT EXISTS.
select a.*
from tbl a
where not exists
(select *
from tbl b
where b.name=a.name
and b.flag=0)
and a.flag=1;