Реляционное деление: найти каждый уникальный набор "дочерних" значений в столбце
После долгих поисков, кажется, наиболее relational division
проблемы целевых групп с соответствующими членами. Возможно, у меня проблемы с ключевыми словами, но я хочу что-то немного другое: учитывая родителей / группу и набор детей / участников, как мне найти каждую уникальную комбинацию членов, независимо от родителя?
Используя следующий пример источника
CREATE TABLE #m (Parent char(1), ChildID int)
INSERT INTO #m
VALUES ('a',1), ('a', 2), ('a',4),
('b',1), ('b', 3), ('b',4),
('c',1), ('c', 4), ('c',2),
('d',1), ('d',4),
('e',3), ('e', 1),
('f',4),
('g',3), ('g', 4), ('g',1);
SELECT * FROM #m
Я бы искал результат, подобный (1, 2, 4), (1, 3, 4), (1, 4), (1, 3), (4), выраженный в виде новой временной таблицы (для присоединения вернуться к #m
так, чтобы каждый Parent
можно указать на его "хэш", а не на его соответствие Parent
)
Есть много вариантов синтаксиса в этом материале; этот вид имеет самое большое значение для меня, но не получил ответа. Извинения за дублирование я не могу найти.
РЕДАКТИРОВАТЬ: желаемый результат, выраженный в виде набора результатов SQL:
UParent ChildID
------- -----------
u1 1
u1 2
u1 4
u2 1
u2 3
u2 4
u3 1
u3 4
u4 1
u4 3
u5 4
3 ответа
Понятно, вам нужны "уникальные" комбинации детей независимо от порядка.
Следующее получает родителей, которые эквивалентны:
select m1.Parent as Parent1, m2.Parent as Parent2
from (select m.*, count(*) over (partition by Parent) as NumKids
from #m m
) m1 join
(select m.*, count(*) over (partition by Parent) as NumKids
from #m m
) m2
on m1.ChildID = m2.ChildID
group by m1.Parent, m2.Parent
having count(*) = max(m1.NumKids) and max(m1.NumKids) = max(m2.NumKids);
Теперь мы можем получить то, что вы хотите, используя это
with parents as (
select m1.Parent as Parent1, m2.Parent as Parent2
from (select m.*, count(*) over (partition by Parent) as NumKids
from #m m
) m1 join
(select m.*, count(*) over (partition by Parent) as NumKids
from #m m
) m2
on m1.ChildID = m2.ChildID
group by m1.Parent, m2.Parent
having count(*) = max(m1.NumKids) and max(m1.NumKids) = max(m2.NumKids)
)
select distinct m.*
from (select min(Parent2) as theParent
from parents
group by Parent1
) p join
#m m
on p.theParent = m.Parent;
Если вы хотите новый идентификатор вместо старого, используйте:
select dense_rank() over (partition by m.Parent) as NewId, m.ChildID
в select
,
Это использует for xml
создать отсортированный список дочерних идентификаторов, который используется в качестве предложения раздела функции rank().
select M.Parent,
M.ChildID
from (
select M1.Parent,
M1.ChildID,
rank() over(partition by (
select cast(ChildID as varchar(11))+','
from #m as M2
where M1.Parent = M2.Parent
order by M2.ChildID
for xml path('')
)
order by M1.Parent) as rn
from #m as M1
) as M
where M.rn = 1;
Поправьте меня, если я ошибаюсь в том, как хранятся ваши данные, разве это уже не в том формате, в каком вы хотите их видеть.
Я пробовал этот запрос на основе данных вашего примера, и он выдает ожидаемый набор результатов. посмотри здесь
SELECT 'u' + CAST(DENSE_RANK() OVER (ORDER BY Parent) AS VARCHAR(10)) AS UParent
,ChildID
FROM #m
Набор результатов
╔═════════╦═════════╗
║ UParent ║ ChildID ║
╠═════════╬═════════╣
║ u1 ║ 1 ║
║ u1 ║ 2 ║
║ u1 ║ 4 ║
║ u2 ║ 1 ║
║ u2 ║ 3 ║
║ u2 ║ 4 ║
║ u3 ║ 1 ║
║ u3 ║ 4 ║
║ u3 ║ 2 ║
║ u4 ║ 1 ║
║ u4 ║ 4 ║
║ u5 ║ 3 ║
║ u5 ║ 1 ║
║ u6 ║ 4 ║
║ u7 ║ 3 ║
║ u7 ║ 4 ║
║ u7 ║ 1 ║
╚═════════╩═════════╝