2011-11-09 5 views
1

J'ai une table qui contient des informations sur les groupes. Il peut y avoir un nombre quelconque de membres dans un groupe. Il y a un identifiant de groupe et ensuite un identifiant d'élément. Je veux pouvoir en une seule instruction de déterminer si oui ou non un ensemble donné existe dans la tableTSql égalité sur les groupes de lignes

@groupTable est un exemple des données qui existe déjà dans la base de données

@inputData est les données que je veulent voir si elle existe déjà dans @groupTable

declare @groupData table 
(
    groupIdentifier int, 
    elementIdentifier uniqueidentifier 
) 

insert into @groupData values 
(1, 'dfce40b1-3719-4e4c-acfa-65f728677700'), 
(1, '89e7e6be-cee8-40a7-8135-a54659e0d88c') 

declare @inputData table 
(
    tempGroupIdentifier int, 
    elementIdentifier uniqueidentifier 
) 

insert into @inputData values 
(42, 'dfce40b1-3719-4e4c-acfa-65f728677700'), 
(42, '89e7e6be-cee8-40a7-8135-a54659e0d88c'), 
(55, 'dfce40b1-3719-4e4c-acfa-65f728677700'), 
(55, '2395a42c-94f4-4cda-a773-221b26ea5e44'), 
(55, 'f22db9df-a1f4-4078-b74c-90e34376eff6') 

maintenant, je veux exécuter une requête qui montrera la relation des ensembles, montrant que IdentifiantGroupe est associée à qui tempGroupIdentifier. S'il n'y a pas d'ensemble correspondant alors j'ai besoin de le savoir aussi.

desired output: 
groupIdentifier, tempGroupIdentifier 
1, 42 
null, 55 

Quelqu'un at-il des suggestions sur la façon d'aborder ce problème?

Je pourrais probablement faire pivoter les lignes et concaténer tous elementIdentifiers dans une chaîne géante pour chaque groupe qui fait alors l'égalité, mais cela ne semble pas être une bonne solution.

+0

Si vous avez à la fois sous forme de tableaux (réel et température), ne serait pas une gauche join faire le travail? ou suis-je en train de rater le vrai problème ici? – Syska

+0

Dans vos données d'exemple, la valeur 'dfce40b1-3719-4e4c-acfa-65f728677700' existe deux fois dans votre table @inputdata; était-ce intentionnel? –

+0

@Syska: oui, mais ce n'est pas "par ligne" mais "par ensemble de lignes" – gbn

Répondre

1
SELECT 
     (
     CASE WHEN matchCount = gdCount AND matchCount = idCount 
      THEN groupIdentifier 
      ELSE NULL 
     END) groupIdentifier, 
     cj.tempGroupIdentifier 
    FROM 
    (
    SELECT gd.groupIdentifier, id.tempGroupIdentifier, COUNT(1) matchCount 
    FROM @groupData gd 
    CROSS JOIN @inputData id 
    WHERE id.elementIdentifier = gd.elementIdentifier 
    GROUP BY gd.groupIdentifier, id.tempGroupIdentifier) as cj 
    CROSS APPLY (SELECT COUNT(groupIdentifier) from @groupData gdca WHERE gdca.groupIdentifier = cj.groupIdentifier) as gdc(gdCount) 
    CROSS APPLY (SELECT COUNT(tempGroupIdentifier) from @inputData idca WHERE idca.tempGroupIdentifier = cj.tempGroupIdentifier) as idc(idCount) 
+0

wow. Je comprends ce que vous faites mais je ne suis pas sûr que ça va évoluer avec cette CROSS JOIN. Et FYI sur le COUNT http://stackoverflow.com/questions/1221559/count-vs-count1/1221649#1221649 – gbn

+0

Peut être améliorée en pré-qualifiant des allumettes avec la concordance de compte. (Deux ensembles sont égaux si aucun d'entre eux ne contient d'éléments non présents dans un autre ensemble -> le nombre d'éléments est le même). N'ont pas regardé exec plan – ImplexOne

+0

Merci qui a l'air bien. Un changement que j'ai fait est de ne faire que renvoyer des correspondances, de sorte que le cas soit simplement renvoyé à groupIdentifier et que l'on ajoute 'where matchCount = gdCount et matchCount = idCount'. Comme c'était le cas, il renvoyait des doublons lorsque l'ensemble groupData était plus petit (ne contenait qu'une ligne) et que le groupe d'entrée était une correspondance partielle (2 lignes 1 correspondant à l'ensemble de groupe) – BrandonAGr

3
SELECT DISTINCT 
    T1.tempgroupIdentifier, T2.GroupIdentifier 
FROM 
    (
    SELECT 
     COUNT(*) OVER (PARTITION BY tempgroupIdentifier) AS GroupCount, 
     ROW_NUMBER() OVER (PARTITION BY tempgroupIdentifier ORDER BY elementIdentifier) AS GroupRN, 
     tempgroupIdentifier, elementIdentifier 
    FROM 
     @inputData 
    ) T1 
    LEFT JOIN 
    (
    SELECT 
     COUNT(*) OVER (PARTITION BY GroupIdentifier) AS GroupCount, 
     ROW_NUMBER() OVER (PARTITION BY GroupIdentifier ORDER BY elementIdentifier) AS GroupRN, 
     GroupIdentifier, elementIdentifier 
    FROM 
     @groupData 
    ) T2 ON T1.elementIdentifier = T2.elementIdentifier AND 
         T1.GroupCount = T2.GroupCount AND 
         T1.GroupRN = T2.GroupRN 

Edit: cela va aussi faire face à la même valeur dans un ensemble donné

+1

Top notch, autre que theres une virgule manquante :-) (Y at-il un moyen de l'éditer, sans faire 5 autres petites modifications) – Syska

+0

oui, je n'ai pas de limite sur mon propre message – gbn

+0

Cela ne semble pas fonctionner lorsqu'il y a des correspondances partielles entre des groupes de même taille.Si @inputData est modifié pour être inséré dans les valeurs @inputData (42, 'dfce40b1-3719-4e4c-acfa-65f728677700'), (42, '89e7e6be-cee8-40a7-8135-a54659e0d88c'), (55 , 'dfce40b1-3719-4e4c-acfa-65f728677700'), (55, '2395a42c-94f4-4cda-a773-221b26ea5e44') 'Alors la requête retournera un résultat incorrect – BrandonAGr

Questions connexes