Pregunta

Este es mi problema sql - hay 3 tablas:

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

Lo que significa que Pablo (Id = 1) y Joe (Id = 2) están en el equipo de Fútbol (Lists.Id = 1), Paul y Jenny en el equipo de baloncesto, etc ...

Ahora necesito una instrucción SQL que devuelve el Lists.Id de una combinación específica Nombre: En el que las listas son Paul, Joe y Jenny los únicos miembros de esa lista? Sólo contestar Lists.Id = 4 (Breakfast Club) - pero no 5 (Midnight Club), ya que Tina está en esa lista, también.

Lo he intentado con combinaciones internas y consultas 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)

Parece un poco complicado, eh? Cómo optimizar eso? Sólo necesito que Lists.Id en que los nombres específicos están en (y sólo estos nombres y nadie más). Tal vez con SELECT IN?

Saludos,  Dennis

¿Fue útil?

Solución

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;

Editar : Se ha corregido gracias al comentario de Chris Gow; la subselección es necesario excluir las listas que tienen otras personas en ellos. Editar 2 Se ha corregido el nombre de la tabla gracias a comentario de Dennis

Otros consejos

Utilizando la solución de Carl Manaster como punto de partida que se me ocurrió:

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

Actualizado:

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

Sólo estaba resolviendo un problema recientemente y que pueden funcionar bien para su caso también. Puede ser una exageración.

Tomé el enfoque de crear una lista de las asociaciones de candidatos que pueden ser la solución correcta y, a continuación, utilizando una tabla de cursor o cola para pasar por las soluciones correctas probable que hacer la validación completa.

En mi caso esto fue implementado por hacer como

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

A continuación, se puede comparar el recuento y la suma de comprobación agregada contra tus datos de búsqueda (es decir, sus 3 nombres para comprobar si hay). Si no hay filas coincide, está garantizado para tener coincidencias. Si cualquier fila coincide a continuación, puede ir a través y hacer una unión de ese parentid específica para validar si hay alguna discrepancia entre los conjuntos de filas.

Claro como el barro? :)

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top