#sql #db2 #exists #relational-division
#sql #db2 #существует #реляционное разделение
Вопрос:
Рассмотрим, что в таблице есть n строк с ИМЕНЕМ и специализацией.
NAME SPECIALITY
AA X
AA Y
BB X
CC X
CC Y
CC Z
Мне требовались имена, чья специализация включала X и Y. В результате я должен получить AA и CC.
Я сталкиваюсь с where exists, но у меня пока не получается правильно сформулировать это:
SELECT DISTINCT NAME
FROM SAMPLE
WHERE EXISTS (
SELECT SPECIALITY
FROM SAMPLE
WHERE SPECIALITY IN ('X','Y')
);
В результате отображаются все имена. Я не смог правильно его взломать. Не могли бы вы, пожалуйста, помочь разобраться?
Комментарии:
1. извините.. это была опечатка
Ответ №1:
используйте агрегацию
select name
from tab
where SPECIALITY in ('X','Y')
group by name
having count(distinct SPECIALITY)=2
и в вашем запросе я могу отредактировать, как показано ниже
SELECT DISTINCT NAME
FROM SAMPLE t1
WHERE EXISTS (SELECT SPECIALITY FROM
SAMPLE t2
WHERE SPECIALITY IN ('X','Y') and
t1.NAME=t2.NAME
having count(distinct SPECIALITY)=2
);
Комментарии:
1. наличие count (отдельная СПЕЦИАЛИЗАЦИЯ) = 2 означает?
2. @Gayathri это означает, что для каждого имени будет учитываться отдельная СПЕЦИАЛИЗАЦИЯ
3. для каждого имени учитывается уникальная специализация? для человека специальность не добавляется дважды, не так ли?
4. @Gayathri не дает вам правильно понять, что вы на самом деле хотите знать
Ответ №2:
Вы можете использовать self join
следующим образом:
select distinct t1.NAME from SAMPLE t1 join SAMPLE t2
on t1.NAME = t2.NAME
and t1.SPECIALITY = 'X' and t2.SPECIALITY = 'Y'
Ответ №3:
Вы можете выполнить простое self
join
действие над таблицей, чтобы получить желаемый результат, как показано ниже.
SELECT t1.NAME
FROM yourtable t1
INNER JOIN yourtable t2
ON t1.NAME = t2.NAME
WHERE t1.speciality = 'x'
AND t2.speciality = 'y'
Приведенный выше запрос покажет все, names
имеющие оба speciality
x
и y
.
Ответ №4:
Вы можете использовать EXISTS
вот так:
SELECT name
FROM sample AS tx
WHERE speciality = 'x'
AND EXISTS (
SELECT 1
FROM sample AS ty
WHERE ty.name = tx.name
AND ty.speciality = 'y'
)
Он найдет все x
строки, в которых существует y
строка.
Ответ №5:
EXISTS
для версии требуется два EXISTS
:
SELECT S.*
FROM SAMPLE S
WHERE EXISTS (SELECT 1 FROM SAMPLE S1 WHERE S.NAME = S1.NAME AND S1.SPECIALITY = 'X') AND
EXISTS (SELECT 1 FROM SAMPLE S1 WHERE S.NAME = S1.NAME AND S1.SPECIALITY = 'Y');
Однако простая агрегация также должна работать :
SELECT S.NAME
FROM SAMPLE S
WHERE SPECIALITY IN ('X', 'Y')
GROUP BY NAME
HAVING MIN(SPECIALITY) <> MAX(SPECIALITY);
Ответ №6:
Требуемый вам оператор связи известен как divide, он же поставщик, который поставляет все детали.
В SQL нет оператора divide, поэтому вы должны использовать свой собственный, в зависимости от того, хотите ли вы точные значения или остатки и т.д.
Но если у вас всегда будет только два жестко запрограммированных значения, тогда вы можете сделать все намного проще:
SELECT NAME FROM SAMPLE WHERE SPECIALITY IN = 'X'
INTERSECT
SELECT NAME FROM SAMPLE WHERE SPECIALITY IN = 'Y'