0

これは私のSQLの問題です-3つのテーブルがあります:

名前リストListHasNames
Id Name Id Desc ListsId NamesId
= -------- ------------ ----------------
1ポール1サッカー11
2ジョー2バスケットボール12
3ジェニー3ピンポン21
4ティナ4朝食クラブ23
              5ミッドナイトクラブ32
                                   3 3
                                   4 1
                                   4 2
                                   4 3
                                   5 1
                                   5 2
                                   5 3
                                   5 4

つまり、ポール(Id = 1)とジョー(Id = 2)はサッカーチーム(Lists.Id = 1)に、ポールとジェニーはバスケットボールチームに所属しています...

ここで、特定の名前の組み合わせのLists.Idを返すSQLステートメントが必要です。Paul、Joe、およびJennyがそのリストの唯一のメンバーであるリストはどれですか。Lists.Id = 4(Breakfast Club)のみに回答しますが、Tinaもそのリストに含まれているため、5(Midnight Club)には回答しません。

内部結合とサブクエリで試してみました。

SELECT Q1.Lists_id FROM

((
SELECT Lists_Id FROM
  T1として名前を付けます
  listhasnames as T2
どこ
  (T1.Name ='Paul')および
  (T1.Id = T2.Names_ID)および
   (((
     SELECT count(*)FROM
      listhasnames as Z1
     ここで(Z1.lists_id = T2.lists_Id)
    )= 3)

)AS Q1

インナージョイン(


SELECT Lists_Id FROM
  T1として名前を付けます
  listhasnames as T2
どこ
  (T1.Name ='Joe')および
  (T1.Id = T2.Names_ID)および
  ((
    (SELECT count(*)FROM
      listhasnames as Z1
     WHERE(Z1.Lists_id = T2.lists_id)
    )= 3)

)AS Q2

オン(Q1.Lists_id = Q2.Lists_id)



インナージョイン(


SELECT Lists_Id FROM
  T1として名前を付けます
  listhasnames as T2
どこ
  (T1.Name ='Jenny')および
  (T1.Id = T2.Names_ID)および
  ((
    (SELECT count(*)FROM
      listhasnames as Z1
     WHERE(Z1.Lists_id = T2.lists_id)
    )= 3)

)AS Q3

オン(Q1.Lists_id = Q3.Lists_id)

少し複雑に見えますね それを最適化する方法は?特定の名前が含まれているLists.Idのみが必要です(これらの名前のみが必要で、他には誰もいません)。たぶんSELECTINで?

よろしく、デニス

4

4 に答える 4

2
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;

編集:ChrisGowのコメントのおかげで修正されました。副選択は、他の人がいるリストを除外するために必要です。 編集2デニスのコメントのおかげでテーブル名を修正しました

于 2009-05-27T19:01:46.177 に答える
2

出発点としてCarlManasterのソリューションを使用して、私は次のことを思いつきました。

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
于 2009-05-27T20:41:36.113 に答える
1

更新しました:

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'))
于 2009-05-27T17:58:30.763 に答える
0

私は最近、あなたのケースでもうまくいくかもしれない問題を解決していました。やり過ぎかもしれません。

私は、正しい解決策となる可能性のある候補の関連付けのリストを作成し、カーソルまたはキューテーブルを使用して、おそらく正しい解決策を調べて完全な検証を行うというアプローチを取りました。

私の場合、これは次のようにして実装されました

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

次に、カウントと集計チェックサムをルックアップデータ(つまり、チェックする3つの名前)と比較できます。一致する行がない場合は、一致しないことが保証されます。行が一致する場合は、その特定のParentIdを調べて結合し、行セット間に不一致があるかどうかを検証できます。

泥のように澄んでいますか?:)

于 2009-05-27T19:56:31.150 に答える