2013-05-17 5 views
3

Je rencontre des problèmes avec une requête SQL que je dois construire pour afficher des données dans une grille.Numéros de ligne utilisant le groupe par et plusieurs colonnes

J'ai cette table temporaire comme ci-dessous (je mets des numéros au lieu de l'adresse e-mail pour l'exemple):

GroupID | Email1 | Email2 
null | 1 | 2 
null | 1 | 2 
null | 1 | null 
null | 3 | 1 
null | 2 | 2 
null | 4 | 2 
null | 5 | 6 
null | 6 | null 

J'ai besoin de mettre à jour la table afin de définir le GroupID comme décrit ci-dessous: Si email1 ou email2 correspond à n'importe quel autre enregistrement, cet enregistrement doit avoir le même groupId que l'autre. Par exemple (en utilisant le tableau ci-dessus):

GroupID | Email1 | Email2 
**1** | 1 | 2 
**1** | 1 | 2 
**1** | 1 | null 
**1** | 3 | 1 
**1** | 2 | 2 
**1** | 4 | 2 
**2** | 5 | 6 
**2** | 6 | null 

J'ai essayé quelque chose comme ça:

UPDATE a 
SET a.GroupId = b.GroupId 
FROM #temp a 
INNER JOIN (SELECT Email, 
        ROW_NUMBER() OVER (ORDER BY ISNULL(Email,'zzzzzzzz')) GroupId 
      FROM (SELECT Email1 Email 
        FROM #temp 
        GROUP BY Email1 
        UNION ALL 
        SELECT Email2 Email 
        FROM #temp     
        GROUP BY Email2 
       ) c 
      GROUP BY Email 
      ) b 
ON a.Email1 = b.Email OR 
    a.Email2 = b.Email OR 
    (b.Email IS NULL AND a.Email1 IS NULL AND a.Email2 IS NULL) 

Mais cela ne fonctionne pas un je compte ... Par exemple le cas où il est le Email2 c'est égal à l'Email 1 n'est pas reconnu comme le même groupe ... Comment puis-je faire fonctionner cette requête comme je le voudrais? Est-ce même possible?

[EDIT] 2013/15/17 14:15: En acte, les règles, je voulais dire « Si EMAIL1 ou email 2 matchs EMAIL1 ou mail2 de tout autre document devrait l'être de la même groupID »

+0

Je pense que les règles sont incomplètes: "* Si email1 ou email2 correspond à un autre enregistrement, cet enregistrement doit avoir le même groupId que l'autre *". Avec juste cette règle, il serait juste de donner à toutes les lignes le même GroupID. Ce qui est beaucoup plus simple et plus facile à mettre en œuvre, mais probablement pas ce dont vous avez besoin. Alors quoi d'autre avez-vous besoin? – RBarryYoung

+0

Quel RDBMS (SQLite, SQLServer, MySQL, etc) est-ce? –

Répondre

4

Cela ne peut pas être effectué dans un seul JOIN car il peut y avoir de très longues chaînes d'emails à traverser, par exemple 1, 2 ->2, 3 ->3, 4 -> ... ->99, 100. (Vous pouvez éventuellement utiliser un CTE récursive pour le faire en une seule déclaration --working autour des questions GROUP BY en quelque sorte -. Mais vous savez ce que je veux dire)

est ici une façon de le faire (SQL Server 2005 et en haut):

WITH E AS (
    SELECT 
     Num = Row_Number() OVER (ORDER BY (SELECT 1)), 
     * 
    FROM dbo.EmailGroups 
) 
UPDATE E 
SET E.GroupID = E.Num 
; 

WHILE @@RowCount > 0 BEGIN 
    UPDATE E 
    SET E.GroupID = X.MinGroupID 
    FROM 
     dbo.EmailGroups E 
     INNER JOIN (
     SELECT 
      E1.GroupID, 
      MinGroupID = Min(E2.GroupID) 
     FROM 
      dbo.EmailGroups E1 
      INNER JOIN dbo.EmailGroups E2 
       ON E1.Email1 IN (E2.Email1, E2.Email2) 
       OR E1.Email2 IN (E2.Email1, E2.Email2) 
     GROUP BY 
      E1.GroupID 
     HAVING 
      E1.GroupID <> Min(E2.GroupID) 
    ) X ON E.GroupID = X.GroupID 
    ; 
END; 

See this working in a SQL Fiddle. Cela aura pour résultat que chaque ensemble chaîné de lignes ayant le même GroupID, distinct de tous les autres GroupIDs (mais ils ne seront pas séquentiels, il y aura des lacunes). Si vous avez besoin qu'ils soient séquentiels, effectuez une mise à jour finale pour définir le GroupID à DENSE_RANK() OVER (ORDER BY GroupID) - ceci est montré dans le Fiddle.

+0

. . Faites attention aux valeurs 'in' et NULL. Je pense que votre requête fonctionne mais vous voulez être sûr que vous ne suivez pas une chaîne de valeurs NULL. Et, vous voulez être sûr que vous correspondez à l'une ou l'autre valeur si l'on est NULL. –

+0

Oh oui, j'utilise SQL Server 2008. Désolé pour le retard! – Guigui

+0

@GordonLinoff A moins que 'SET ANSI_NULLS' soit' OFF', tout va bien. – ErikE

Questions connexes