Хорошо, вот моя попытка. Возможно, можно реализовать эту логику так, чтобы не требовалось 5 обращений к одной и той же таблице, но сейчас я не могу об этом думать.
Логика здесь заключается в том, чтобы сначала удалить дубликаты объектов, а затем подсчитать оставшиеся идентификаторы. Подзапрос NOT IN
представляет объекты, которые имеют соответствующий объект с меньшим идентификатором. Подзапрос объединяет параметры двух объектов t1 и t2, а затем подсчитывает, сколько параметров соответствует каждой паре t1 / t2. Если количество совпадающих параметров совпадает с количеством параметров в t1 и в t2, то t2 и t1 являются совпадениями, и мы должны исключить t1 из набора результатов.
DECLARE @tab TABLE (ID int, parameter varchar(2));
INSERT INTO @tab
SELECT 1, 'A' UNION ALL
SELECT 1, 'B' UNION ALL
SELECT 2, 'A' UNION ALL
SELECT 3, 'A' UNION ALL
SELECT 3, 'B' UNION ALL
SELECT 4, 'A' UNION ALL
SELECT 5, 'C' UNION ALL
SELECT 5, 'D';
SELECT
COUNT(DISTINCT t.ID) AS num_groups
FROM
@tab AS t
WHERE
t.ID NOT IN
(SELECT
t1.ID AS ID1
FROM
@tab AS t1
INNER JOIN
@tab AS t2
ON
t1.ID > t2.ID AND
t1.parameter = t2.parameter
GROUP BY
t1.ID,
t2.ID
HAVING
COUNT(*) = (SELECT COUNT(*) FROM @tab AS dupe WHERE dupe.ID = t1.ID) AND
COUNT(*) = (SELECT COUNT(*) FROM @tab AS dupe WHERE dupe.ID = t2.ID)
);
Результат на SQL Server 2008 R2:
num_groups
3
Что касается объектов с 0 параметрами, то это зависит от того, как они хранятся, но обычно вам просто нужно добавить один к ответу выше, если есть какие-либо объекты с 0 параметрами.