WITH Nodes AS
(
SELECT DENSE_RANK() OVER (ORDER BY Part, PartRank) SetId
, [ID]
FROM
(
SELECT [ID], 1 Part, DENSE_RANK() OVER (ORDER BY [E-mail]) PartRank
FROM dbo.Customer
UNION ALL
SELECT [ID], 2, DENSE_RANK() OVER (ORDER BY Phone) PartRank
FROM dbo.Customer
) A
),
Links AS
(
SELECT DISTINCT A.Id, B.Id LinkedId
FROM Nodes A
JOIN Nodes B ON B.SetId = A.SetId AND B.Id < A.Id
),
Routes AS
(
SELECT DISTINCT Id, Id LinkedId
FROM dbo.Customer
UNION ALL
SELECT DISTINCT Id, LinkedId
FROM Links
UNION ALL
SELECT A.Id, B.LinkedId
FROM Links A
JOIN Routes B ON B.Id = A.LinkedId AND B.LinkedId < A.Id
),
TransitiveClosure AS
(
SELECT Id, Id LinkedId
FROM Links
UNION
SELECT LinkedId Id, LinkedId
FROM Links
UNION
SELECT Id, LinkedId
FROM Routes
),
UniqueCustomers AS
(
SELECT Id, MIN(LinkedId) UniqueCustomerId
FROM TransitiveClosure
GROUP BY Id
)
SELECT A.Id, A.[E-mail], A.Phone, B.UniqueCustomerId
FROM dbo.Customer A
JOIN UniqueCustomers B ON B.Id = A.Id
Ниже приведен код, который я использовал, чтобы показать, почему приведенный выше код не работает должным образом. Идентификатор - это уникальный идентификатор для каждой учетной записи, адрес электронной почты - это одно поле для агрегирования, а телефон - другое. Все, что я прокомментировал, это то, что я пытался добавить в запросе Company_Name, но тогда я понял, что есть проблема. Если я смогу пройти группировку по телефону и электронной почте, следующим шагом к этой проблеме будет заставить ее работать и с названием компании.
With Customers AS
(
Select 1 as [ID]
,'John@G.com' as [E-mail]
,'111-111-1111' as [Phone]
--,'Mcdonaldss' as [Company_Name]
union all
Select 0, 'Harry@g.com', '121-212-1212'--,'Mmcdonalds'
union all
Select 2, 'Grant@g.com', '111-111-1111'--, 'Mcdonallds'
union all
Select 3, 'John@G.com', '222-222-2222'--, 'Mcdonnalds'
union all
select 4, 'Harry@g.com', '222-222-2222'--, 'Mccdonalds'
union all
Select 5, 'Jack@g.com', '444-444-4444'--, 'Wendys'
--union all
--Select 10, 'Sarah@g.com', '888-888-8888', 'Mcdonald'
--union all
--Select 9, 'Sarah@g.com', '999-999-9999', 'Mcdoonalds'
--union all
--Select 8, 'Jessy@g.com', '999-999-9999', 'Mcds'
--Union all
--Select 7, 'Jessy@g.com', '777-777-7777', 'Mcdanalds'
--Union all
--Select 6, 7, '777-777-7777', 'Mcdonolds'
--Union all
--Select 11, 8, '222-222-2222', 'Mcds'
),
Nodes AS
(
SELECT DENSE_RANK() OVER (ORDER BY Part, PartRank) SetId
, [ID]
FROM
(
SELECT c.[ID], '1 email' Part, DENSE_RANK() OVER (ORDER BY [E-mail]) PartRank
FROM Customers as [c]
UNION ALL
SELECT c.[ID], '2 phone', DENSE_RANK() OVER (ORDER BY Phone) PartRank
FROM Customers as [c]
--union all
--SELECT c.[ID], '3 Compnay_Name', DENSE_RANK() OVER (ORDER BY Next_level) PartRank
-- FROM #Customer as [c]
) A
),
Links AS
(
SELECT DISTINCT A.Id, B.Id LinkedId
FROM Nodes A
JOIN Nodes B ON B.SetId = A.SetId AND B.Id < A.Id
)
--Select * from links
,
roads AS
(
SELECT DISTINCT Id, Id LinkedId
FROM Customers as [c]
UNION ALL
SELECT DISTINCT Id, LinkedId
FROM links
UNION ALL
SELECT A.Id, B.LinkedId
FROM Links A
JOIN Roads B ON B.Id = A.LinkedId AND B.LinkedId < A.Id
)
--Select * from Roads
,
TransitiveClosure AS
(
SELECT Id, Id LinkedId
FROM Links
UNION
SELECT LinkedId Id, LinkedId
FROM Links
UNION
SELECT Id, LinkedId
FROM roads
)
--Select * from TransitiveClosure
,
UniqueCustomers AS
(
SELECT Id, MIN(LinkedId) UniqueCustomerId
FROM TransitiveClosure
GROUP BY Id
)
SELECT A.Id, A.[E-mail], A.Phone, dense_rank() over (order by B.UniqueCustomerId) as [Company_no]
FROM Customers A
JOIN UniqueCustomers B ON B.Id = A.Id
В этом примере мне нужен идентификатор 0, 1,2, 3 и 4 имеют одинаковое значение Company_no. Тем не менее, поскольку идентификатор 0 ниже идентификатора 1, идентификатор 1 не связан с идентификатором 0. Это означает, что все, что связано с идентификатором 1, также не ссылается на идентификатор 0 и разделяет результаты. ID 5 мой контроль. Это не должно объединяться ни с чем. Все другие закомментированные учетные записи будут также соответствовать McDonalds, когда будет добавлено название компании, но эту вторую часть я смогу решить после того, как смог точно соединить два поля.
Желаемый вывод
ID E-mail Phone Unique ID
---- ------------------- -------------- ------------------------------
0 Harry@g.com 121-212-1212 ─┐
1 John@G.com 111-111-1111 |
2 Grant@g.com 111-111-1111 ├─ 1 (Mcdonalds)
3 John@G.com 222-222-2222 |
4 Harry@g.com 222-222-2222 ─┘
---- ------------------- -------------- ------------------------------
5 Jack@g.com 444-444-4444 ─── 2 (Wendys)
Обновление Мне удалось заставить код делать то, что я хочу, удалив упомянутый выше фильтр-нарушитель, увеличив максимальную рекурсию и добавив ограничение на количествопетли в разделе дорог, как показано ниже. Это дает желаемый результат и работает для всех трех полей, однако при переходе от 12 строк к 104 000 ... это не практическое решение. Это превратило 1000 записей в миллион и даже не было закончено. Любые советы, чтобы предотвратить бессмысленное зацикливание, или по-другому решать эту группировку?
Текущий код
With Customers AS
(
Select 1 as [ID]
,'John@G.com' as [E-mail]
,'111-111-1111' as [Phone]
,'Mcdonaldss' as [Company_Name]
union all
Select 0, 'Harry@g.com', '121-212-1212','Mmcdonalds'
union all
Select 2, 'Grant@g.com', '111-111-1111', 'Mcdonallds'
union all
Select 3, 'John@G.com', '222-222-2222', 'Mcdonnalds'
union all
select 4, 'Harry@g.com', '222-222-2222', 'Mccdonalds'
union all
Select 5, 'Jack@g.com', '444-444-4444', 'Wendys'
union all
Select 10, 'Sarah@g.com', '888-888-8888', 'Mcdonald'
union all
Select 9, 'Sarah@g.com', '999-999-9999', 'Mcdoonalds'
union all
Select 8, 'Jessy@g.com', '999-999-9999', 'Mcds'
Union all
Select 7, 'Jessy@g.com', '777-777-7777', 'Mcdanalds'
Union all
Select 6, 'Mark@g.com', '777-777-7777', 'Mcdonolds'
Union all
Select 11, 'Carol@g.com', '222-222-2222', 'Mcds'
Union all
Select 12, 'carol@g.com', '101-010-1010','Mcdooonalds'
),
Nodes AS
(
SELECT DENSE_RANK() OVER (ORDER BY Part, PartRank) SetId
, [ID]
FROM
(
SELECT c.[ID], '1 email' Part, DENSE_RANK() OVER (ORDER BY [E-mail]) PartRank
FROM Customers as [c]
UNION ALL
SELECT c.[ID], '2 phone', DENSE_RANK() OVER (ORDER BY Phone) PartRank
FROM Customers as [c]
union all
SELECT c.[ID], '3 Company_Name', DENSE_RANK() OVER (ORDER BY Company_Name) PartRank
FROM Customers as [c]
) A
),
Links AS
(
SELECT DISTINCT A.Id, B.Id LinkedId
FROM Nodes A
JOIN Nodes B ON B.SetId = A.SetId AND B.Id <> A.Id
)
--Select * from links
,
roads AS
(
SELECT DISTINCT Id, Id LinkedId, 0 as [count]
FROM Customers as [c]
UNION ALL
SELECT DISTINCT Id, LinkedId, '0'
FROM links
UNION ALL
SELECT
A.Id, B.LinkedId, B.[count]+1
FROM Links A
JOIN Roads B ON B.Id = A.LinkedId AND B.LinkedId <> A.Id
Where b.[count] <= 10
)
--Select * from Roads
,
TransitiveClosure AS
(
SELECT Id, Id LinkedId
FROM Links
UNION
SELECT LinkedId Id, LinkedId
FROM Links
UNION
SELECT Id, LinkedId
FROM roads
)
--Select * from TransitiveClosure
,
UniqueCustomers AS
(
SELECT Id, MIN(LinkedId) UniqueCustomerId
FROM TransitiveClosure
GROUP BY Id
)
SELECT A.Id, A.[E-mail], A.Phone, A.company_Name, dense_rank() over (order by B.UniqueCustomerId) as [Company_no]
FROM Customers A
JOIN UniqueCustomers B ON B.Id = A.Id
option (maxrecursion 32767)