0

这是我的 sql 问题 - 有 3 个表:

名称列表 ListHasNames
Id 名称 Id 描述 ListsId NamesId
=-------- ------------ ----------------
1 保罗 1 足球 1 1
2 乔 2 篮球 1 2
3 珍妮 3 乒乓球 2 1
4 蒂娜 4 早餐俱乐部 2 3
              5 午夜俱乐部 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 在篮球队,等等...

现在我需要一个返回特定名称组合的 Lists.Id 的 SQL 语句:在哪些列表中 Paul、Joe 和 Jenny 是该列表的唯一成员?只回答 Lists.Id=4(早餐俱乐部) - 但不回答 5(午夜俱乐部),因为 Tina 也在该列表中。

我已经尝试过使用 INNER JOINS 和 SUB QUERIES:

选择 Q1.Lists_id FROM

(
选择 Lists_Id FROM
  名称为 T1,
  列表名称为 T2
在哪里
  (T1.Name='Paul') 和
  (T1.Id=T2.Names_ID) 和
   ( (
     选择计数(*)从
      列表名称为 Z1
     其中(Z1.lists_id = T2.lists_Id)
    ) = 3)

) 作为第一季度

内部联接 (


选择 Lists_Id FROM
  名称为 T1,
  列表名称为 T2
在哪里
  (T1.Name='Joe') 和
  (T1.Id=T2.Names_ID) 和
  (
    (选择计数(*)来自
      列表名称为 Z1
     哪里(Z1.Lists_id = T2.lists_id)
    ) = 3)

) 作为第二季度

开(Q1.Lists_id=Q2.Lists_id)



内部联接 (


选择 Lists_Id FROM
  名称为 T1,
  列表名称为 T2
在哪里
  (T1.Name='Jenny') 和
  (T1.Id=T2.Names_ID) 和
  (
    (选择计数(*)来自
      列表名称为 Z1
     哪里(Z1.Lists_id = T2.lists_id)
    ) = 3)

) 作为第三季度

开(Q1.Lists_id=Q3.Lists_id)

看起来有点复杂,嗯?如何优化它?我只需要包含特定名称的 Lists.Id(并且只有这些名称,没有其他人)。也许选择输入?

问候,丹尼斯

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;

编辑:由于 Chris Gow 的评论而更正;子选择对于排除其他人的列表是必要的。 编辑 2由于丹尼斯的评论更正了表名

于 2009-05-27T19:01:46.177 回答
2

使用 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
于 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 回答