Учитывая следующие две таблицы в 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
Я пытаюсь найти GroupID (ы) из таблицы GroupItems, где ItemIDs точно соответствуют содержимому таблицы 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 обычно содержит около десятка строк. Эта функция вызывается довольно регулярно. Я ищу более эффективный способ получить те же результаты.