如何优化M:N的关系查询3个表
-
06-09-2019 - |
题
这是我的SQL问题 - 有3个表:
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
这意味着,保罗(ID = 1)和乔(ID = 2)是在足球队(Lists.Id = 1),保罗和Jenny在篮球队等...
现在我需要它返回一个特定的名称组合的Lists.Id SQL语句: 在该名单是保罗,乔和珍妮该名单的唯一成员?答案只有Lists.Id = 4(早餐俱乐部) - 但不是5(午夜俱乐部),因为Tina是在该列表中了。
我已经与内连接,并试图它SUB QUERIES:
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)
看起来有点复杂,恩?如何优化? 我只需要一个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牌九的评论;子选择要排除有其他人对他们的名单。 修改2 强>更正表名由于丹尼斯的评论
其他提示
使用卡尔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名检查)。如果没有相匹配的行,你保证没有匹配。如果任何行匹配你就可以办理,并做了入一个特定的ParentId,以验证是否存在该行集之间的差异。
清除泥? :)
不隶属于 StackOverflow