Подсчет последовательных элементов в SQL Server - PullRequest
2 голосов
/ 22 марта 2010

Возникла проблема с запросом, который я пытаюсь написать. У меня есть таблица, в которой перечислены люди, которым было отправлено электронное письмо. Есть битовый столбец с именем Active, который устанавливается в true, если они ответили. Но мне нужно посчитать количество последовательных электронных писем, которые человек неактивировал с момента его первого или последнего активного письма.

Например, эта базовая таблица показывает, что одному человеку было отправлено 9 писем. Они были активны в течение двух писем (3 и 5). Таким образом, их неактивное число будет равно 4, как мы рассчитываем начиная с адреса электронной почты № 6.

PersonID(int)    EmailID(int)    EmailDate(datetime)    Active(bit)
1                1               2009-07-18 19:56:20    0
1                2               2009-08-18 19:56:20    0
1                3               2009-09-18 19:56:20    1
1                4               2009-10-18 19:56:20    0
1                5               2009-11-18 19:56:20    1
1                6               2009-12-18 19:56:20    0
1                7               2010-01-18 19:56:20    0
1                8               2010-02-18 19:56:20    0
1                9               2010-03-18 19:56:20    0

Любые указатели или помощь будут великолепны.

С уважением Грег

Ответы [ 3 ]

1 голос
/ 22 марта 2010

Мой первый разрез:

SELECT PersonID, COUNT(*) FROM Table T1
WHERE Active = 0 AND EmailDate > 
   (SELECT MAX(EMailDate) FROM Table T2 
       WHERE T2.PersonID = T1.PersonID AND Active = 1)
GROUP BY PersonID

Обратите внимание, что для этого решения требуется, чтобы каждый отвечал хотя бы на одно письмо. Если вы хотите включить людей, которые были неактивны с самого первого отправленного им электронного письма, вам нужно обернуть этот термин (MAX (EmailDate)) в какой-то IFNULL (), возвращающий дату до даты начала системы для NULL .

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

0 голосов
/ 06 октября 2016

Версия ответа @ Larry-Lustig, которая использует COALESCE для возврата подсчетов для пользователей без электронных писем:

SELECT PersonID, COUNT(*) FROM Table T1
WHERE Active = 0 AND EmailDate > 
   COALESCE (
       (SELECT MAX(EMailDate) FROM Table T2 
           WHERE T2.PersonID = T1.PersonID AND T2.Active = 1),
       DATEFROMPARTS(1900,1,1))
GROUP BY PersonID
0 голосов
/ 22 марта 2010

Попробуйте:

SET NOCOUNT ON
DECLARE @Emails table (PersonID int, EmailID int,  Active bit)
INSERT @Emails VALUES ( 1,1,0)
INSERT @Emails VALUES ( 1,2,0)
INSERT @Emails VALUES ( 1,3,1)
INSERT @Emails VALUES ( 1,4,0)
INSERT @Emails VALUES ( 1,5,1)
INSERT @Emails VALUES ( 1,6,0)
INSERT @Emails VALUES ( 1,7,0)
INSERT @Emails VALUES ( 1,8,0)
INSERT @Emails VALUES ( 1,9,0)
INSERT @Emails VALUES ( 2,1,0)
INSERT @Emails VALUES ( 2,2,0)
INSERT @Emails VALUES ( 2,3,0)
INSERT @Emails VALUES ( 2,4,0)
INSERT @Emails VALUES ( 2,5,0)
INSERT @Emails VALUES ( 2,6,0)
INSERT @Emails VALUES ( 3,1,1)
INSERT @Emails VALUES ( 3,2,1)
INSERT @Emails VALUES ( 3,3,1)
INSERT @Emails VALUES ( 3,4,1)
SET NOCOUNT OFF


SELECT
    e.PersonID,COUNT(e.EmailID) AS CountInactive
    FROM @Emails e
        LEFT OUTER JOIN (SELECT
                             PersonID,MAX(EmailID) AS LastActive
                             FROM @Emails
                             WHERE Active=1
                             GROUP BY PersonID
                        ) dt ON e.PersonID=dt.PersonID
    WHERE e.EmailID>ISNULL(dt.LastActive,0)
    GROUP BY e.PersonID

ВЫХОД:

PersonID    CountInactive
----------- -------------
1           4
2           6

(2 row(s) affected)

РЕДАКТИРОВАТЬ после редактирования ОП, тот же вывод, что и выше:

SELECT
    e.PersonID,COUNT(e.EmailID) AS CountInactive
    FROM @Emails e
        LEFT OUTER JOIN (SELECT
                             PersonID,MAX(EmailDate) AS LastActive
                             FROM @Emails
                             WHERE Active=1
                             GROUP BY PersonID
                        ) dt ON e.PersonID=dt.PersonID
    WHERE (e.EmailDate>ISNULL(dt.LastActive,0)) OR dt.PersonID IS NULL
    GROUP BY e.PersonID
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...