Запрос для группировки и исключения из нескольких списков

#sql #tsql

#sql #tsql

Вопрос:

У меня есть таблица SQL (Email_Campaigns) с основным списком кампаний, которые мы запустили:

 Name            DateSent
Campaign01    01/01/2011
Campaign02    01/15/2011
..
Campaign40    10/01/2011
  

У меня есть список клиентов (Email_Received) с их номерами участников и кампаниями, которые они получили:

 PK    MembershipNo    CampaignName
1           123456      Campaign01
2           123456      Campaign02
3           987654      Campaign05
4           111111      Campaign10
  

У меня также есть основной список клиентов MembershipNo (клиенты)

Вопрос: Как мне написать запрос, чтобы перечислить каждую кампанию и подсчитать количество клиентов, которые НЕ получили это электронное письмо? Например (столбец ‘Received’ показан здесь только для справки и не является обязательным, поскольку я знаю, как это вычислить):

 Name          Received    DidNotReceive
Campaign01        1000             9000
Campaign02        3000             7000
..
Campaign40         100             9900
  

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

1. Чтобы ответить на вопрос ниже… Да, безусловно, бывают случаи, когда клиенты получали несколько сообщений электронной почты, и это сделано специально.

Ответ №1:

Вот один из стандартных способов SQL для записи этого:

 SELECT ec.Name, count(c.MembershipNo) AS DidNotReceive
  FROM Customers AS c
     , Email_Campaigns AS ec
 WHERE NOT EXISTS (
    SELECT 1
      FROM Email_Received AS r
     WHERE er.CampaignName = ec.CampaignName
       AND er.MembershipNo = c.MembershipNo)
 GROUP BY ec.Name
 ORDER BY ec.Name;
  

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

1. Спасибо! Я рад, что спросил, потому что раньше у меня было именно то, что у вас было, за исключением предложения «И»… неудивительно, что запрос вращался более 15 минут без результата. :-/

2. @hurleystylee: если это позволяют ваши конкретные условия, вам также следует попробовать ответ Джо Стефанелли, который может быть значительно быстрее с большими таблицами. При необходимости добавьте то DISTINCT , что я упомянул.

Ответ №2:

 SELECT er.CampaignName, 
       COUNT(*) AS Received, 
       (SELECT COUNT(*) FROM Customers) - COUNT(*) AS DidNotReceive
    FROM Email_Received er
    GROUP BY er.CampaignName
    ORDER BY er.CampaignName;
  

Это на самом простом уровне. Вероятно, следует учитывать дополнительные соображения, например, был ли данный клиент активен во время распространения кампании.

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

1. Это должно быть быстрее, чем мой ответ. Однако мой ответ также охватывает случай дублирования записей в Email_Received (люди могут получать несколько электронных писем, по замыслу или по ошибке), что не было исключено в вопросе. Может быть исправлено с помощью COUNT (DISTINCT x). Не уверен, разрешено ли это в tsql.

2. @ErwinBrandstetter T-SQL имеет COUNT(DISTINCT x) .