Как мне запросить каждого человека, который не знает никого, кто посещает занятия?

#sql

#sql

Вопрос:

Я борюсь со следующей проблемой SQL: я должен запросить всех людей, которые не знают никого, кто посещает занятия, используя следующие таблицы:

 ╔═════════╦════════╦═══════════╦═════╗
║ Persons ║        ║           ║     ║
╠═════════╬════════╬═══════════╬═════╣
║ id      ║ name   ║ address   ║ age ║
║ 1       ║ Teddy  ║ Utrecht   ║ 96  ║
║ 2       ║ Harun  ║ Texas     ║ 64  ║
║ 3       ║ Egbert ║ Rome      ║ 68  ║
║ 4       ║ John   ║ Amsterdam ║ 39  ║
╚═════════╩════════╩═══════════╩═════╝
╔═══════╦════════════╦════════════╗
║ Knows ║            ║            ║
╠═══════╬════════════╬════════════╣
║ id    ║ personA_id ║ personB_id ║
║ 2512          ║
║ 2613          ║
║ 2732          ║
║ 2834          ║
╚═══════╩════════════╩════════════╝
╔══════════════╦═══════════╦══════════╗
║ TakesClasses ║           ║          ║
╠══════════════╬═══════════╬══════════╣
║ id           ║ person_id ║ class_id ║
║ 35150       ║
║ 36151       ║
║ 37152       ║
║ 38153       ║
║ 39254       ║
║ 40255       ║
║ 41256       ║
╚══════════════╩═══════════╩══════════╝
  

После долгого времени попыток выполнения разных запросов следующий запрос является наиболее близким к желаемому результату:

 select distinct name 
from Persons P
where P.id NOT IN 
(select person_id 
 from TakesClasses T join Knows K 
 on T.person_id = K.personA_id
 where class_id IS NOT NULL)
  

Кажется, я получаю больше результатов, чем необходимо для этого запроса (Харун, Эгберт и Джон), но я не могу найти ошибку, которую я делаю. Может кто-нибудь, пожалуйста, помочь мне?

Комментарии:

1. Не сохраняйте возраст. Большинство людей, как правило, становятся старше с каждым годом, и ваши данные скоро устареют. Вместо этого сохраните дату / год рождения.

2. Я считаю, что (select person_id это должно быть (select personB_id , однако таблица knows должна быть симметричной

Ответ №1:

используйте это:

 select P.id, name 
from Persons P
where P.id NOT IN 
(select K.personA_id
from TakeClasses T join Knows K 
on T.person_id = K.personB_id
)
  

Комментарии:

1. К сожалению, это не решило проблему. Я все еще получаю слишком много результатов на выходе. Мне нужны люди, которые не знают никого, кто посещает занятия.

2. проверьте мой запрос, я только что отредактировал, я думаю, он работает сейчас

Ответ №2:

Этот тип проблемы предполагает not exists :

 select p.*
from persons p
where not exists (select 1
                  from takesclasses tc join
                       knows k
                       on tc.personB_id = k.person_id
                  where k.personA_id = p.id
                 );
  

Предложение correlation связывает подзапрос с внешним запросом.

Обратите внимание, что это предполагает, что knows отношения симметричны. Итак, если A «знает» B, то B «знает», что A также находится в таблице.

Редактировать:

Я настоятельно рекомендую вам никогда не использовать NOT IN подзапросы with. Он ведет себя не так, как ожидалось, если какие-либо значения, возвращаемые в подзапросе, являются NULL . В этом случае, однако, вы можете сделать:

 select p.*
from persons p
where p.id not in (select k.personA_id
                   from takesclasses tc join
                        knows k
                        on tc.personB_id = k.person_id
                  );
  

Комментарии:

1. Не было бы более эффективным использовать идентификатор пользователя непосредственно из takesclasses таблицы как отдельный? А затем присоединиться к лицам, чтобы получить имя? Предполагается, что количество людей, посещающих занятия, меньше, чем общее количество людей (т. Е. Кто-то не будет посещать какие-либо занятия).

2. @ChatterOne . name , , В takesclasses таблице нет, поэтому вам нужно. join persons Кроме того, select distinct это дорогостоящая операция, поэтому я предпочитаю избегать ее.

3. Да, именно поэтому я сказал And then join Persons to get the name . Но если вы хотите избежать distinct, альтернативы нет.

4. Я должен использовать оператор NOT IN для этого упражнения. Однако ваше решение дает правильный результат. Спасибо за это. У вас есть предложение для этого запроса с использованием NOT IN? 🙂

5. Спасибо за помощь и объяснение 🙂