Объединение WHERE EXISTS и IN в SQL

#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'