문제

이것은 내 SQL 문제입니다 - 3 개의 테이블이 있습니다.

이름은 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

이는 Paul (ID = 1)과 Joe (ID = 2)가 축구 팀 (Lists.id = 1), 농구 팀의 Paul과 Jenny 등에 있다는 것을 의미합니다.

이제 목록을 반환하는 SQL 명령문이 필요합니다. 특정 이름 조합의 ID : 그 목록은 그 목록의 유일한 멤버 인 Paul, Joe 및 Jenny는 무엇입니까? Tina도 그 목록에 있기 때문에 5 (아침 클럽) - 5 (Midnight Club)가 아닙니다.

내부 조인 및 하위 쿼리로 시도했습니다.

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)

조금 복잡해 보입니다. 그것을 최적화하는 방법? 특정 이름이있는 목록 만 필요합니다 (그리고이 이름과 다른 사람 만). 아마도 select in?

안부, 데니스

도움이 되었습니까?

해결책

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;

편집하다: Chris Gow의 의견 덕분에 수정되었습니다. 다른 사람들이있는 목록을 제외하려면 하위 선택이 필요합니다.편집 2 Dennis의 의견 덕분에 테이블 이름을 수정했습니다

다른 팁

Carl Manaster의 솔루션을 출발점으로 사용하여 다음과 같이 생각했습니다.

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

업데이트 :

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

나는 최근에 당신의 사건에도 잘 작동 할 수있는 문제를 해결하고있었습니다. 과잉 일 수 있습니다.

올바른 솔루션 일 수있는 후보 협회 목록을 작성한 다음 커서 또는 큐 테이블을 사용하여 올바른 솔루션을 통해 전체 검증을 수행하는 방법을 사용했습니다.

필자의 경우 이것은 같은 행동으로 구현되었습니다

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

그런 다음 조회 데이터와 카운트 및 집계 체크섬을 비교할 수 있습니다 (예 : 3 개의 이름을 확인할 수 있습니다). 행이 일치하지 않으면 일치하지 않습니다. 행이 일치하는 경우 행 세트 사이에 불일치가 있는지 확인하기 위해 해당 특정 부모의 조인을 수행 할 수 있습니다.

진흙처럼 깨끗합니까? :)

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top