2010-03-22 9 views
2

Vous avez un problème avec une requête que j'essaie d'écrire. J'ai un tableau qui répertorie les personnes qui ont reçu un e-mail. Il y a une colonne bit nommée Active qui est définie sur true si elle a répondu. Mais j'ai besoin de compter le nombre de courriels consécutifs où la personne a été inactive depuis son premier courriel ou son dernier courriel actif.Comptage d'éléments consécutifs dans SQL Server

Par exemple, ce tableau de base montre qu'une personne a reçu 9 courriels. Ils ont été actifs dans deux des courriels (3 & 5). Donc, leur nombre inactif serait de 4, car nous comptons à partir du numéro 6 par courriel.

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 

Tout pointeur ou aide serait formidable.

Cordialement Greg

+0

Mon 2c - la colonne active devrait être appelée HasResponded pour indiquer effectivement l'action. –

+0

Vos données d'échantillon sont-elles une description précise du problème? Ce que je veux dire, c'est que les EmailID sont toujours * garantis * consécutifs (sans rupture de numérotation) dans chaque valeur PersonID? –

+0

Il existe des dates associées aux e-mails. Pensez que je vais modifier le post pour refléter cela. – Greg

Répondre

1

Ma première coupe:

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 

Notez que cette solution exige que chaque personne répond au moins un e-mail. Si vous souhaitez inclure des personnes inactives à partir du premier e-mail qui leur a été envoyé, vous devez inclure ce terme (MAX (EmailDate)) dans une sorte d'IFNULL() renvoyant une date avant la date de début du système pour les valeurs NULL . En outre, comme le signale KM ci-dessous, si quelqu'un n'est pas actuellement inactif (ils ont répondu à l'e-mail le plus récent), ils ne seront pas dans le jeu de résultats. Je pense que cela répond probablement à vos besoins mais, si ce n'est pas le cas, faites-le moi savoir.

+0

ne fonctionne pas s'il y a plus d'un employé dans la table. –

+0

Salut Larry, merci pour cela, il semble retourner de bons résultats sur mon ensemble de données. Je vous remercie!! – Greg

+0

@KM: Pourquoi pas? Inner SELECT est corrélé à PersonID externe. –

0

pour cette solution:

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 

SORTIE:

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

(2 row(s) affected) 

EDIT après modification de l'OP, même sortie comme ci-dessus:

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

Bonjour KM, cela donne également de bons résultats. Je vous remercie. – Greg

0

Une version de la réponse de @ Larry-Lustig qui utilise COALESCE pour retourner compte pour les utilisateurs sans e-mails:

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