Есть ли способ сгруппировать учетные записи вместе, которые совпадают на разных полях, и сгруппировать, на что эти группы группируются? - PullRequest
0 голосов
/ 14 октября 2019

Мне нужно создать новый уникальный идентификатор для компаний, которые будут иметь несколько учетных записей с нами. У меня есть названия компаний, но я знаю, что есть опечатки, которые отбрасывают данные. У меня есть другие уникальные поля, с которыми я хотел бы работать, чтобы сгруппировать данные вместе, когда это так.

У меня есть пара сотен тысяч учетных записей, которые имеют по крайней мере указанное информационное название компании, телефон и электронную почту. почта. В случае, если название компании отличается между двумя учетными записями, но учетные записи совпадают с любым другим полем, я бы хотел, чтобы SQL присвоил ему тот же уникальный идентификатор (предполагаемая опечатка). Кроме того, в случае, если дополнительная учетная запись совпадает с названием компании учетной записи 2, но не совпадает ни с одним другим полем для чего-либо еще, я бы хотел, чтобы он получил такой же уникальный идентификатор, как и предыдущие две (подозреваемая повторяющаяся опечатка).

SQL-запрос типа GROUP BY с условием ИЛИ

Это похоже на то, что я пытаюсь сделать, за исключением того, что мне нужно добавить третье поле. Однако я заметил, что после попытки использовать предложенный ответ (ниже) он объединит только несколько компаний, основываясь на количестве их идентификаторов. Похоже, это связано с тем, что он добавил фильтр b.linkedId

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)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...