Присвойте тот же ключ дублирующимся записям для идентификации в SQL - PullRequest
0 голосов
/ 11 мая 2019

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

Я могу использовать diff_rank для ранжирования повторяющихся записей с тем же номером, но застрял потом, не знаю, как назначить новые ключи NewCustID для всех записей.

Исходные таблицы и образцы данных

create table Cust_init(
    NewCustID int,
    DW_CustID int,
    FirstName varchar(50),
    LastName varchar(50),
    Email varchar(50),
    MailAddress varchar(50),
    Phone varchar(50)
)

create table MergedCust(
    NewCustID int,
    DW_CustID int,
    FirstName varchar(50),
    LastName varchar(50),
    Email varchar(50),
    MailAddress varchar(50),
    Phone varchar(50)
)


insert into dbo.cust_init(DW_CustID,FirstName, LastName,Email,MailAddress,Phone) 
values(11,'Ahmad','Raza','ahmaddba@gmail.com','154 Zafarwal, Narowaal','0345 2876543'),
      (12,'Iftikhan','Khan','iffikhan@gmail.com','12 A DHA Phase ','0303 56871298'),
      (13,'Iftikhan','Khan','iffikhan@gmail.com','12 A DHA Phase ','0303 56871298'),
      (14,'Mohsin','Khan','mohsinkaz@gmail.com','55 shadab nagar, Lahore','0301 6791255'),
      (15,'Mohsin','Khan','mohsinkaz@gmail.com','55 shadab nagar, Lahore','0301 6791255'),
      (16,'Hamid','Alvi','hamidalvi@gmail.com','12 A DHA Phase 2','0300 7071266'),
      (17,'Hamid','Alvi','hamidalvi@gmail.com','12 A DHA Phase 2','0300 7071266'),
      (18,'Hamid','Alvi','hamidalvi@gmail.com','12 A DHA Phase 2','0300 7071266'),
      (19,'Hamid','Alvi','hamidalvi@gmail.com','12 A DHA Phase 2','0300 7071266'),
      (20,'Hamid','Alvi','hamidalvi@gmail.com','12 A DHA Phase 2','0300 7071266');

После вставки данных таблица Cust_init должна выглядеть следующим образом:

NewCustID   |DW_CustID  |FirstName  |LastName   |Email                  |MailingAddress         |Phone
NULL        |   11      |Ahmad      |Raza       |ahmaddba@gmail.com     |154 Zafarwal           |0345 2876543
NULL        |   12      |Iftikhan   |Khan       |iffikhan@gmail.com     |12 A DHA Phase         |0303 56871298
NULL        |   13      |Iftikhan   |Khan       |iffikhan@gmail.com     |12 A DHA Phase         |0303 56871298
NULL        |   14      |Mohsin     |Khan       |mohsinkaz@gmail.com    |55 shadab nagar        |0301 6791255
NULL        |   15      |Mohsin     |Khan       |mohsinkaz@gmail.com    |55 shadab nagar        |0301 6791255
NULL        |   16      |Hamid      |Alvi       |hamidalvi@gmail.com    |12 A DHA Phase 2       |0300 7071266
NULL        |   17      |Hamid      |Alvi       |hamidalvi@gmail.com    |12 A DHA Phase 2       |0300 7071266
NULL        |   18      |Hamid      |Alvi       |hamidalvi@gmail.com    |12 A DHA Phase 2       |0300 7071266
NULL        |   19      |Hamid      |Alvi       |hamidalvi@gmail.com    |12 A DHA Phase 2       |0300 7071266
NULL        |   20      |Hamid      |Alvi       |hamidalvi@gmail.com    |12 A DHA Phase 2       |0300 7071266

Фаза 1
Я хочу определить дубликаты записей на основе FirstName, LastName, Email и назначить новые ключи для NewCustID (начальный числовой номер изначально равен 1 затем максимальное значение + 1 после начальной загрузки). Числовые ключи NewCustID начинаются с 1 и уникальны для каждой записи, за исключением дубликатов. В случае дублирования, один числовой ключ должен быть связан со всеми связанными дублирующимися записями.

После назначения NewCustID таблица Cust_init должна выглядеть следующим образом.

NewCustID   |DW_CustID  |FirstName  |LastName   |Email                  |MailingAddress         |Phone
1           |   11      |Ahmad      |Raza       |ahmaddba@gmail.com     |154 Zafarwal           |0345 2876543
2           |   12      |Iftikhan   |Khan       |iffikhan@gmail.com     |12 A DHA Phase         |0303 56871298
2           |   13      |Iftikhan   |Khan       |iffikhan@gmail.com     |12 A DHA Phase         |0303 56871298
3           |   14      |Mohsin     |Khan       |mohsinkaz@gmail.com    |55 shadab nagar        |0301 6791255
3           |   15      |Mohsin     |Khan       |mohsinkaz@gmail.com    |55 shadab nagar        |0301 6791255
4           |   16      |Hamid      |Alvi       |hamidalvi@gmail.com    |12 A DHA Phase 2       |0300 7071266
4           |   17      |Hamid      |Alvi       |hamidalvi@gmail.com    |12 A DHA Phase 2       |0300 7071266
4           |   18      |Hamid      |Alvi       |hamidalvi@gmail.com    |12 A DHA Phase 2       |0300 7071266
4           |   19      |Hamid      |Alvi       |hamidalvi@gmail.com    |12 A DHA Phase 2       |0300 7071266
4           |   20      |Hamid      |Alvi       |hamidalvi@gmail.com    |12 A DHA Phase 2       |0300 7071266

Фаза 2
После назначения NewCustID в таблице Cust_Init я хочу скопировать только уникальные строки в таблицу MergedCust. Сохранение только одной строки с минимальным DW_CustID для повторяющихся записей.

NewCustID   |DW_CustID  |FirstName  |LastName   |Email                  |MailingAddress         |Phone
1           |   11      |Ahmad      |Raza       |ahmaddba@gmail.com     |154 Zafarwal           |0345 2876543
2           |   12      |Iftikhan   |Khan       |iffikhan@gmail.com     |12 A DHA Phase         |0303 56871298
3           |   14      |Mohsin     |Khan       |mohsinkaz@gmail.com    |55 shadab nagar        |0301 6791255
4           |   16      |Hamid      |Alvi       |hamidalvi@gmail.com    |12 A DHA Phase 2       |0300 7071266

Мои усилия
Я придумал следующий sql для ранжирования строк с одинаковым номером для дубликатов, но не уверен, как правильно обновить NewCustID.

;WITH cte as (
    SELECT  NewCustID, DW_CustID, FirstName,LastName, Email, MailAddress, Phone,
            dense_rank() OVER (ORDER BY FirstName , LastName, Email ) as RN
    FROM dbo.cust_init 
)
select RN,FirstName , LastName, Email 
from cte 

Результирующий набор выглядит следующим образом, я хотел бы изначально назначить RN для NewCustID, чтобы проверить, выполняет ли он цель.

RN  |FirstName  |LastName   |Email
1   |Ahmad      |Raza       |ahmaddba@gmail.com
2   |Hamid      |Alvi       |hamidalvi@gmail.com
2   |Hamid      |Alvi       |hamidalvi@gmail.com
2   |Hamid      |Alvi       |hamidalvi@gmail.com
2   |Hamid      |Alvi       |hamidalvi@gmail.com
2   |Hamid      |Alvi       |hamidalvi@gmail.com
3   |Iftikhan   |Khan       |iffikhan@gmail.com
3   |Iftikhan   |Khan       |iffikhan@gmail.com
4   |Mohsin     |Khan       |mohsinkaz@gmail.com
4   |Mohsin     |Khan       |mohsinkaz@gmail.com

Ответы [ 4 ]

1 голос
/ 11 мая 2019

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

Чтобы подойти к этому с помощью одного запроса, выможно использовать рекурсивные CTE.К сожалению, SQL Server не поддерживает массивы, поэтому для избежания циклов необходимо отслеживать ранее введенные вами идентификаторы, а это много строковых операций.

Вот запрос:

with cte as (
      select dw_custId, dw_custId as other_ci,
             convert(varchar(max), concat(',', dw_custId, ',')) as cis,
             convert(varchar(max), ',' + email + ',') as emails,
             convert(varchar(max), ',' + phone + ',') as phones,
             convert(varchar(max), ',' + mailaddress + ',') as mailaddresses,
             1 as lev
      from cust_init
      union all
      select cte.dw_custId, ci.dw_custId,
             concat(cte.cis, ci.dw_custId, ','),
             (case when cte.emails not like concat('%,', ci.email, ',%') then concat(cte.emails, ci.email, ',') else cte.emails end),
             (case when cte.phones not like concat('%,', ci.phone, ',%') then concat(cte.phones, ci.phone, ',') else cte.phones end),
             (case when cte.mailaddresses not like concat('%,', ci.mailaddress, ',%') then concat(cte.mailaddresses, ci.mailaddress, ',') else cte.mailaddresses end),
             lev + 1
      from cte join
           cust_init ci
           on cte.emails like concat('%,', ci.email, ',%') or
              cte.phones = concat('%,', ci.phone, ',%') or
              cte.mailaddresses = concat('%,', ci.mailaddress, ',%')
      where cte.cis not like concat('%,', ci.dw_custId, ',%') and lev < 10
     )
select dw_custid, min(other_ci), dense_rank() over (order by min(other_ci)) as newCustId
from cte
group by dw_custid;

Здесь - это дБ <> скрипка.

РЕДАКТИРОВАТЬ:

Вы можете использовать это в update:

with cte ( . . . )
update t2
    set newCustId = x.newCustId
    from (select dw_custid, min(other_ci), dense_rank() over (order by min(other_ci)) as newCustId
          from cte
          group by dw_custid
         ) x join
         table2 t2
         on t2.dw_custid = x.dw_custid;
0 голосов
/ 11 мая 2019

Попробуйте это-

SELECT 
ROW_NUMBER() OVER (ORDER BY A.min_cust_id) NewCustID,
B.DW_CustID,
B.FirstName,
B.LastName,
B.Email,
B.MailAddress,
B.Phone
FROM 
(
    SELECT email, MIN(dw_custID) min_cust_id
    FROM cust_init
    GROUP BY EMAIL
)A
INNER JOIN cust_init B ON A.min_cust_id = B.DW_CustID
0 голосов
/ 11 мая 2019

Это дает желаемый результат, который вы опубликовали выше. Просто используйте ROW_NUMBER для нумерации ваших дубликатов, а затем возьмите первый.

WITH CTE AS
(SELECT NewCustID, DW_custID,FirstName,LastName,Email,MailAddress,Phone, 
ROW_NUMBER() OVER(Partition by NewCustID ORDER BY NewCustID) RN
from #Cust_init
)

INSERT INTO #MergedCust
select NewCustID,DW_custID,FirstName,LastName,Email,MailAddress,Phone 
from CTE where RN = 1

SELECT * from #MergedCust

EDIT: Учитывая ваши данные выше, я предположил, что вы уже выяснили, как назначить NewCustID. Вот как я это сделал:

UPDATE #Cust_init set NewCustID =  DR
       FROM #Cust_init t1
       INNER JOIN (SELECT dw_custid, DENSE_RANK () OVER(order by firstname,lastname,email) DR from #Cust_init) t2
       on t1.DW_CustID = t2.DW_CustID
0 голосов
/ 11 мая 2019
WITH customers AS (
  SELECT 
    Dense_rank() OVER(
      ORDER BY 
        c.firstname, 
        c.lastname, 
        c.email
    ) AS rn, 
    * 
  FROM 
    #cust_init AS c) 
  INSERT INTO #mergedcust 
  SELECT 
    c.rn AS newcustid, 
    -1 AS DW_CustID, 
    c.firstname, 
    c.lastname, 
    c.email, 
    c.mailaddress, 
    c.phone 
  FROM 
    customers AS c 
  GROUP BY 
    c.rn, 
    c.firstname, 
    c.lastname, 
    c.email, 
    c.mailaddress, 
    c.phone;
SELECT 
  * 
FROM 
  #mergedcust
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...