T-SQL:按组成员查找组
给定SQL Server 2005中的以下两个表:T-SQL:按组成员查找组,sql,tsql,Sql,Tsql,给定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 E
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表通常包含十几行。此函数被相当定期地调用。我正在寻找一种更有效的方法来获得相同的结果。假设:
没有相关信息缺失
ItemID是PKs,因此是唯一的
您不需要重复组/项组合的GroupID
这应该起作用:
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具有唯一的组/项组合,则无需联接。假设:
ItemID值只能大于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;
此解决方案返回A和B,其中一个不起作用。在样本数据上,它返回A和B。只应返回B。在T-Sql中,COUNT函数通常需要一个参数*。我想我没有错过任何相关的东西。如果两个组包含与ItemList完全相同的项,那么它们都应该被返回。我现在看到了这一点-但是,在我看来,您的示例有一个不一致的地方导致了这一点。您在GroupItems中有一个ItemID,但在ItemList中不存在。这是预期的吗?这似乎违反了这些概念——尽管您没有明确列出它们,但如果我看到ItemList和GroupItems表,我希望GroupItems表与ItemList和GroupList之间存在外键关系。对此,我深表歉意。假设GroupItems表中的ItemID列和ItemList表中的ItemID都有第三个表ItemMaster的外键。GroupItems和ItemList表之间没有外键关系。GroupItems.ItemID的值通常不包含在ItemList表中。OK-2连接到ItemMaster,并猜测GroupMaster以确保每个组/项目组合只有一个条目,然后匹配计数。这应该行得通。有什么方法可以用来创建一种启发式方法,先找到一个小得多的列表,然后检查剩余值。任何关于ListItem表的特许权都会有所帮助,例如,如果给定的范围GroupID和ItemID值都不为null,则总是x个项目数或总是在x-y范围内。ItemList表中的值也是非空且唯一的。除此之外,我认为我无法对数据做出任何保证。在您的生产环境中,您是否试图使ItemList表中的所有十几行都匹配。基本上,itemlist提供了一种模式,您需要使用它,findItemID始终大于0。我没有考虑过使用左连接。我将试用它,看看它与我原来的函数相比性能如何。
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;