Question

est mon problème sql - il y a 3 tables:

Names         Lists                ListHasNames
Id Name       Id Desc              ListsId  NamesId
=--------     ------------         ----------------
1  Paul       1  Football          1        1
2  Joe        2  Basketball        1        2
3  Jenny      3  Ping Pong         2        1
4  Tina       4  Breakfast Club    2        3
              5  Midnight Club     3        2
                                   3        3
                                   4        1
                                   4        2
                                   4        3
                                   5        1
                                   5        2
                                   5        3
                                   5        4

Ce qui signifie que Paul (Id = 1) et Joe (Id = 2) sont dans l'équipe de football (Lists.Id = 1), Paul et Jenny dans l'équipe de basket-ball, etc ...

Maintenant, je besoin d'une instruction SQL qui renvoie la Lists.Id d'une combinaison spécifique Nom: Où les listes sont Paul, Joe et Jenny les seuls membres de cette liste? Réponse seulement Lists.Id = 4 (Breakfast Club) - mais pas 5 (Midnight Club) parce que Tina est dans cette liste, aussi.

Je l'ai essayé avec et SUB REJOINT INNER INTERROGATIONS:

SELECT Q1.Lists_id FROM

(
SELECT Lists_Id FROM
  names as T1,
  listhasnames as T2
WHERE
  (T1.Name='Paul') and
  (T1.Id=T2.Names_ID) and
   ( (
     SELECT count(*) FROM
      listhasnames as Z1
     where (Z1.lists_id = T2.lists_Id)
    ) = 3)

) AS Q1

INNER JOIN (


SELECT Lists_Id FROM
  names as T1,
  listhasnames as T2
WHERE
  (T1.Name='Joe') and
  (T1.Id=T2.Names_ID) and
  (
    (SELECT count(*) FROM
      listhasnames as Z1
     WHERE (Z1.Lists_id = T2.lists_id)
    ) = 3)

) AS Q2

ON (Q1.Lists_id=Q2.Lists_id)



INNER JOIN (


SELECT Lists_Id FROM
  names as T1,
  listhasnames as T2
WHERE
  (T1.Name='Jenny') and
  (T1.Id=T2.Names_ID) and
  (
    (SELECT count(*) FROM
      listhasnames as Z1
     WHERE (Z1.Lists_id = T2.lists_id)
    ) = 3)

) AS Q3

ON (Q1.Lists_id=Q3.Lists_id)

On dirait un peu compliqué, hein? Comment optimiser cela? Je dois seulement que Lists.Id dans lequel les noms spécifiques sont (et seulement ces noms et personne d'autre). Peut-être avec SELECT IN?

Cordialement,  Dennis

Était-ce utile?

La solution

SELECT ListsId
FROM ListHasNames a
WHERE NamesId in (1, 2, 3)
AND NOT EXISTS
(SELECT * from ListHasNames b 
WHERE b.ListsId = a.ListsId 
AND b.NamesId not in (1, 2, 3))
GROUP BY ListsId
HAVING COUNT(*) = 3;

Modifier : Corrigés grâce au commentaire de Chris Gow; la sous-sélection est nécessaire d'exclure des listes qui ont d'autres personnes sur eux. Edit 2 Correction du nom de la table grâce au commentaire de Dennis

Autres conseils

En utilisant la solution de Carl Manaster comme point de départ, je suis venu avec:

SELECT listsid 
FROM listhasnames 
GROUP BY listsid HAVING COUNT(*) = 3
INTERSECT
SELECT x.listsid 
FROM listhasnames x, names n 
WHERE n.name IN('Paul', 'Joe', 'Jenny') 
AND n.id = x.namesid

Mise à jour:

select a.ListsId from
(
    --lists with three names only
    select lhn.ListsId, count(*) as count
    from ListHasNames  lhn
    inner join Names n on lhn.NamesId = n.Id 
    group by lhn.ListsId
    having count(*) = 3
) a
where a.ListsId in (select ListsId from ListHasNames lhn where NamesId = (select NamesId from names where Name = 'Paul'))
and a.ListsId in (select ListsId from ListHasNames lhn where NamesId = (select NamesId from names where Name = 'Joe'))
and a.ListsId in (select ListsId from ListHasNames lhn where NamesId = (select NamesId from names where Name = 'Jenny'))

Je viens de résoudre un problème récemment qui pourrait bien fonctionner pour votre cas aussi. Il peut être surpuissant.

Je pris l'approche de la création d'une liste des associations de candidats qui peuvent être la bonne solution, puis en utilisant une table de curseur ou file d'attente pour passer par les solutions susceptibles de faire corriger une validation complète.

a été mis en œuvre dans mon cas, en faisant comme

select
ParentId
count(*) as ChildCount
checksum_agg(checksum(child.*) as ChildAggCrc
from parent join child on parent.parentId = child.parentId

Ensuite, vous pouvez comparer le nombre et la somme de contrôle total par rapport à vos données de recherche (à savoir vos 3 noms pour vérifier pour). Si aucune ligne ne correspond, vous êtes assuré d'avoir aucune correspondance. Si une ligne correspond alors vous pouvez passer et faire une jointure de cette ParentId spécifique pour valider s'il y a des différences entre les ensembles de lignes.

Clair comme la boue? :)

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top