SQL: обнаружение дублирующих клиентов - PullRequest
2 голосов
/ 21 февраля 2012

я пытаюсь создать SQL-запрос, который обнаружит (возможно) дублирующих клиентов в моей базе данных:

У меня есть две таблицы:

  1. Клиент со столбцами: cid, имя, фамилия, zip. Обратите внимание, что cid - это уникальный идентификатор клиента и первичный ключ для этой таблицы.
  2. IgnoreForDuplicateCustomer со столбцами: cid1, cid2. Оба столбца являются внешними ключами, на которые ссылается Customer (cid). Эта таблица используется, чтобы сказать, что клиент с cid1 отличается от клиента с cid2.

Так, например, если у меня есть

  • запись клиента с cid = 1, firstname = "foo", lastname = "anonymous" и zip = "11231"
  • и еще одна запись клиента с cid = 2, firstname = "foo", lastname = "anonymous" и zip = "11231".

Таким образом, мой sql-запрос должен искать клиентов с одинаковыми именем, фамилией и почтовым индексом, и обнаруживать, что клиент с cid = 1 совпадает с клиентом с cid = 2.

Однако можно сказать, что cid клиента = 1 и cid = 2 - это не одно и то же, сохраняя новую запись в таблице IgnoreForDuplicateCustomer, устанавливая cid1 = 1 и cid2 = 2.

Таким образом, обнаружение дублирующих клиентов хорошо работает с этим сценарием SQL-запроса:

SELECT cid, firstname, lastname, zip, COUNT(*) AS NumOccurrences
       FROM Customer
 GROUP BY fistname, lastname,zip
       HAVING ( COUNT(*) > 1 )

Моя проблема в том, что я не могу интегрировать таблицу IgnoreForDuplicateCustomer, чтобы как и в моем предыдущем примере, клиент с cid = 1 и cid = 2 не будет помечен / запрошен как один и тот же, поскольку в таблице IgnoreForDuplicateCustomer есть запись / правило.

Поэтому я попытался расширить свой предыдущий запрос, добавив предложение where:

    SELECT cid, firstname, lastname, COUNT(*) AS NumOccurrences
               FROM Customer    
    WHERE cid NOT IN (
                     SELECT cid1 FROM IgnoreForDuplicateCustomer WHERE cid2=cid 
                     UNION 
                     SELECT cid2 FROM IgnoreForDuplicateCustomer WHERE cid1=cid
                     )  
     GROUP BY firstname, lastname, zip
     HAVING ( COUNT(*) > 1 )

К сожалению, это дополнительное предложение WHERE абсолютно не влияет на мой результат. Есть предложения?

Ответы [ 3 ]

1 голос
/ 21 февраля 2012

Вот вы:

Select a.*
From (
  select c1.cid 'CID1', c2.cid 'CID2'
  from Customer c1 
  join Customer c2 on c1.firstname=c2.firstname 
    and c1.lastname=c2.lastname and c1.zip=c2.zip
    and c1.cid < c2.cid) a
Left Join (
  Select cid1 'CID1', cid2 'CID2'
  From ignoreforduplicatecustomer one
 Union
  Select cid2 'CID1', cid1 'CID2'
  From ignoreforduplicatecustomer two) b on a.cid1 = b.cid1 and a.cid2 = b.cid2
where b.cid1 is null

Это даст вам идентификаторы дубликатов записей из таблицы customer, которых нет в таблице ignoreforduplicatecustomer.

Проверено с:

CREATE TABLE IF NOT EXISTS `customer` (
 `CID` int(11) NOT NULL AUTO_INCREMENT,
 `Firstname` varchar(50) NOT NULL,
 `Lastname` varchar(50) NOT NULL,
 `ZIP` varchar(10) NOT NULL,
 PRIMARY KEY (`CID`)) 
ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=100 ;

INSERT INTO `customer` (`CID`, `Firstname`, `Lastname`, `ZIP`) VALUES
(1, 'John', 'Smith', '1234'),
(2, 'John', 'Smith', '1234'),
(3, 'John', 'Smith', '1234'),
(4, 'Jane', 'Doe', '1234');

И

CREATE TABLE IF NOT EXISTS `ignoreforduplicatecustomer` (
 `CID1` int(11) NOT NULL,
 `CID2` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;


INSERT INTO `ignoreforduplicatecustomer` (`CID1`, `CID2`) VALUES
(1, 2);

Результаты для моей настройки теста:

CID1  CID2
 1     3
 2     3
1 голос
/ 21 февраля 2012

Редактировать согласно комментарию TPete (не пробуйте):

SELECT 
    C1.cid, C1.firstname, C1.lastname
FROM 
    Customer C1,
    Customer C2
WHERE
    C1.cid < C2.cid AND 
    C1.firstname = C2.firstname AND 
    C1.lastname = C2.lastname AND 
    C1.zip = C2.zip AND 
    CAST(C1.cid AS VARCHAR)+' ' +CAST(C2.cid AS VARCHAR) <> 
       (SELECT CAST(cid1 AS VARCHAR)+' '+CAST(cid2 AS VARCHAR) FROM IgnoreForDuplicateCustomer I WHERE I.cid1 = C1.cid AND I.cid2 = C2.cid);

Сначала я думал, что IgnoreForDuplicateCustomer - это поле в таблице клиентов.

0 голосов
/ 21 февраля 2012

сумасшедший, но я думаю, что это работает:)

сначала я присоединяю таблицы клиентов к себе по именам, чтобы получить дубликаты, затем я исключаю ключи из таблицы IgnoreForDuplicateCustomer (объединение происходит потому, что первый запрос возвращаетcid1, cid2 и cid2, cid1

результат будет дублирован, но я думаю, что вы можете получить необходимую информацию

select c1.cid, c2.cid
from Customer c1 
     join Customer c2 on c1.firstname=c2.firstname 
     and c1.lastname=c2.lastname and c1.zip=c2.zip
     and c1.cid!=c2.cid
except 
(
    select cid1,cid2 from IgnoreForDuplicateCustomer
    UNION
    select cid2,cid1 from IgnoreForDuplicateCustomer
)

второй выстрел:

select firstname,lastname,zip from Customer 
group by firstname,lastname,zip 
having (count(*)>1)
except
select c1.firstname, c1.lastname, c1.zip
from Customer c1 join IgnoreForDuplicateCustomer IG on c1.cid=ig.cid1 join Customer c2 on ig.cid2=c2.cid

третий:

select firstname,lastname,zip from (
    select firstname,lastname,zip from Customer 
    group by firstname,lastname,zip 
    having (count(*)>1)
) X
where firstname not in (
select c1.firstname
from Customer c1 join IgnoreForDuplicateCustomer IG on c1.cid=ig.cid1 join Customer c2 on ig.cid2=c2.cid
)
...