2010-03-22 5 views
2

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

Например, эта базовая таблица показывает, что одному человеку было отправлено 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 

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

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

+0

Мой 2с - Активная колонка должна быть вызвана HasResponded на самом деле указывают на действие. –

+0

Являются ли ваши данные образцов точным описанием проблемы? Я имею в виду, что идентификаторы EmailID всегда * гарантированы *, чтобы быть последовательными (без перерывов в нумерации) в пределах каждого значения PersonID? –

+0

Есть даты, связанные с письмами. Думаю, я отредактирую сообщение, чтобы это отразить. – Greg

ответ

1

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

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 ,

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

+0

не работает, если в таблице больше одного сотрудника. –

+0

Привет Ларри, спасибо за это, похоже, что он возвращает хорошие результаты по моему полному набору данных. Спасибо!! – Greg

+0

@KM: Почему бы и нет? Внутренний SELECT соотносится с внешним личным идентификатором. –

0

дать этому попытку:

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) 

EDIT после редактирования параметров порядка, такой же вывод, что и выше:

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 
+0

Привет KM, это также возвращает хорошие результаты. Спасибо. – Greg

0

Вариант ответа @ Ларри-Люстиг, которая использует 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 
Смежные вопросы