Domanda

questo è il mio problema di sql - ci sono 3 tabelle:

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

Il che significa che Paolo (Id = 1) e Joe (Id = 2) sono nella squadra di calcio (Lists.Id = 1), Paolo e Jenny nella squadra di basket, ecc ...

Ora ho bisogno di un'istruzione SQL che restituisce il Lists.Id di una specifica combinazione di nome: In quali liste sono Paul, Joe e Jenny gli unici membri di tale lista? Rispondere solo Lists.Id = 4 (Breakfast Club) - ma non 5 (Midnight Club), perché Tina è in quella lista, anche.

Ho provato con inner join e query SUB:

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)

Sembra un po 'complicato, eh? Come ottimizzare questo? Ho bisogno solo che Lists.Id in cui i nomi specifici sono in (e solo questi nomi e nessun altro). Forse con SELECT IN?

Saluti,  Dennis

È stato utile?

Soluzione

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;

Modifica : corretti grazie a un commento di Chris Gow; la subselect è necessario escludere le liste che hanno altre persone su di loro. Modifica 2 Corretto il nome della tabella grazie al commento di Dennis'

Altri suggerimenti

Utilizzando la soluzione di Carl Manaster come punto di partenza mi si avvicinò con:

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

Aggiornamento:

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'))

Stavo solo risolvere un problema recente che può funzionare bene per il vostro caso. Può essere eccessivo.

Ho preso l'approccio della creazione di un elenco delle associazioni candidati che può essere la soluzione giusta, e quindi utilizzando una tabella di cursore o coda per passare attraverso le soluzioni probabilmente corrette per fare la convalida completa.

Nel mio caso questo è stato attuato facendo come

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

Quindi è possibile confrontare il conteggio e checksum complessivo contro i dati di ricerca (vale a dire i tuoi 3 nomi per verificare la presenza). Se nessuna riga corrispondono, si sono garantiti per non avere corrispondenze. Se qualsiasi riga corrisponde si può quindi passare attraverso e fare un join di quello specifico ParentId per convalidare se ci sono delle discrepanze tra i set di righe.

Chiaro come fango? :)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top