在SQL Server 2005中给出以下两个表:
IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'GroupItems')
DROP TABLE GroupItems;
CREATE TABLE GroupItems (
RowID INT IDENTITY(1,1) PRIMARY KEY
, GroupID CHAR(1)
, ItemID INT
);
IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'ItemList')
DROP TABLE ItemList;
CREATE TABLE ItemList (
ItemID INT PRIMARY KEY
)
INSERT GroupItems ( GroupID, ItemID )
SELECT 'A', 1
UNION SELECT 'A', 2
UNION SELECT 'A', 3
UNION SELECT 'A', 4
UNION SELECT 'B', 1
UNION SELECT 'B', 2
UNION SELECT 'B', 4
UNION SELECT 'C', 1
UNION SELECT 'C', 2
UNION SELECT 'D', 1
UNION SELECT 'D', 4
UNION SELECT 'D', 5
INSERT ItemList ( ItemID )
SELECT 1
UNION SELECT 2
UNION SELECT 4
我正在尝试从表GroupItems中找到GroupID,其中ItemID与表ItemList的内容完全匹配。
在样本数据中,结果应为“B”组。
A组被拒绝,因为它包含一个不在ItemList表中的项目。
C组被拒绝,因为它不包含ItemList表中的所有项目。
D组因两个原因被拒绝。
目前,我正在做类似
的事情DECLARE @ListCount INT;
SELECT @ListCount = COUNT(*) FROM ItemList;
SELECT GI.GroupID FROM GroupItems AS GI
INNER JOIN ItemList AS IL ON IL.ItemID = GI.ItemID
INNER JOIN ( SELECT GroupID FROM GroupItems
GROUP BY GroupID
HAVING COUNT(*) = @ListCOunt ) AS GS ON GS.GroupID = GI.GroupID
GROUP BY GI.GroupID
HAVING COUNT(*) = @ListCount;
此函数提供了我正在寻找的正确结果,但是,在我的生产环境中,GroupItems表有数十万行和数千个唯一的GroupID。 ItemList表通常包含大约十几行。这个函数被定期调用。我正在寻找一种更有效的方法来获得相同的结果。
答案 0 :(得分:0)
假设:
这应该有效:
select GroupID
from GroupItems
inner join ItemMaster
on GroupItems.ItemID = ItemMaster.ItemID
inner join GroupMaster
on GroupItems.GroupID = GroupMaster.GroupID
group by GroupID
having count(*) = (select count(*) from ItemList)
如果GroupItems中有唯一组/项组合的保证,则连接将是不必要的。
答案 1 :(得分:0)
假设:
SELECT t.GroupID FROM ( SELECT GroupItems.GroupID ,count(1) as groupItemsCount ,min(IsNull(ItemList.ItemID, -1)) as minVal FROM GroupItems LEFT JOIN ItemList ON (GroupItems.ItemID = ItemList.ItemID) GROUP BY GroupID ) t WHERE t.groupItemsCount = (SELECT COUNT(1) FROM ItemList) AND (t.minVal > 0)
答案 2 :(得分:0)
您是否考虑过创建一个索引视图来聚合GroupItems上的计数?
CREATE VIEW GroupCounts (groupId, GroupCount) with SCHEMABINDING
AS
SELECT groupId, COUNT_BIG(1) /* I use 1 instead of asterisk by convention */
FROM GroupItems
GROUP BY groupId
CREATE CLUSTERED INDEX IX_GroupCounts on GroupCounts(groupId)
有了这个,您可以使用与您拥有的查询类似的查询,但它应该有更好的性能。
SELECT GS.groupId FROM GroupItems AS GI
INNER JOIN ItemList AS IL ON IL.ItemID = GI.ItemID
INNER JOIN GroupCounts AS GS ON GS.GroupID = GI.GroupID
GROUP BY GS.GroupID
HAVING COUNT(1) = groupCount;