2017-03-29 21 views
1

Ich versuche, potenzielle doppelte Kunden in meiner Datenbank basierend auf den letzten 4 SSN, Nachnamen und DOB zu identifizieren. Die gespeicherte Prozedur, die ich geschrieben habe, identifiziert potentielle Duplikate, aber sie listet sie in einer Zeile auf - ich versuche, aus Gründen der Berichterstattung in separate Zeilen aufzuteilen.Potenzielle Duplikate in verschiedene Zeilen trennen

Mein T-SQL wie folgt aussieht:

DECLARE 
@StartDate DATE = '1/1/2017', 
@EndDate DATE = '3/1/2017'; 

SELECT DENSE_RANK() OVER (ORDER BY c.socialSecurityNumber) AS [SSNRanking] , 
    ROW_NUMBER() OVER (PARTITION BY c.socialSecurityNumber ORDER BY c.socialSecurityNumber) AS [RowNumb] , 
    c.socialSecurityNumber AS [SSN], 
    c.id AS [CustomerID] , 
    c.firstName AS [FirstName] ,  
    c.lastName AS [lastName] , 
    c.birthDate [birthdate] , 
    c.createDate AS [CreateDate] , 
    c2.socialSecurityNumber AS [DupSSN] , 
    c2.id AS [DupCustomerID] , 
    c2.firstName AS [DupFirstName] , 
    c2.lastName AS [DupLastName] , 
    c2.birthDate AS [DupBirthDate] , 
    c2.createDate AS [DupCreateDate] 
FROM dbo.Customers AS [c] 
    INNER JOIN dbo.Customers AS [c2] ON (SUBSTRING(c.socialSecurityNumber,6,4) = SUBSTRING(c2.socialSecurityNumber,6,4) AND c.birthDate = c2.birthDate AND c.lastName = c2.lastName AND c.id <> c2.id) 
    LEFT JOIN dbo.CustomerAddresses AS [CA] ON c.id = CA.customerID    
    LEFT OUTER JOIN dbo.Common_Orders AS [co] ON co.customerID = c.id 
WHERE 
    c.customerStatusTypeID <> 'M' 
    AND C2.customerStatusTypeID <> 'M' 
    AND c.mergedTo IS NULL 
    AND c2.mergedTo IS NULL 
    AND CAST(co.orderDate AS DATE) >= @StartDate 
    AND CAST(co.orderDate AS DATE) <= @EndDate 
    AND c.id = 1234439 
GROUP BY c.socialSecurityNumber , 
    c.id , 
    c.firstName , 
    c.lastName , 
    c.birthDate ,  
    c.createDate , 
    c2.socialSecurityNumber , 
    c2.id , 
    c2.firstName ,   
    c2.lastName , 
    c2.birthDate , 
    c2.createDate 
ORDER BY CAST(c.socialSecurityNumber AS INT) ASC; 

Und Satz meiner Daten wie folgt aussieht:

SSNRanking RowNumb SSN  CustomerID FirstName lastName birthdate CreateDate DupSSN  DupCustomerID DupFirstName DupLastName DupBirthDate DupCreateDate 
1   1  000009915 1234439  GREG  GARRETT 1900-01-01 2014-02-25 000009915 1166084  ADAM   GARRETT  1900-01-01 2013-08-29 

In diesem speziellen Fall, ich habe zwei Benutzer mit denselben letzten 4 des SSN, gleicher Nachname und gleicher DOB - aber andere Vornamen.

Wie kann ich diese zwei Datensätze in separaten Zeilen erscheinen lassen? Idealerweise würde ich gerne sehen:

SSNRanking RowNumb SSN  CustomerID FirstName lastName birthdate CreateDate 
1   1  000009915 1234439  GREG  GARRETT 1900-01-01 2014-02-25 
1   2  000009915 1166084  ADAM  GARRETT 1900-01-01 2013-08-29 

Aber ich bin mir nicht sicher, wie ich dies erreichen kann, wenn ich mich an die gleiche Tabelle anschließe. Vorschläge?

Ich verbinde mit einem Skript, das die zwei fraglichen Tabellen erstellt und Beispieldaten einfügt. Hoffentlich ist das akzeptabel: SQL Script

+0

Können Sie Tabellendefinitionen und Beispieldaten angeben? –

+0

Sicher - Sie benötigen Tabellendefinitionen für die zugrunde liegenden Tabellen oder die Definition der Ergebnistabellen? – MISNole

+0

die zugrunde liegenden Tabellen, aber keine Notwendigkeit für alle Spalten gerade genug, um Ihr Problem zu replizieren und eine Lösung zu finden –

Antwort

1

Dies wird "Unpivot" genannt. Sie können UNPIVOT Operator verwenden, aber ich bevorzuge CROSS APPLY ... VALUES.

Ich werde Ihre Abfrage in CTE umhüllen, ohne es in Details zu betrachten und jede Zeile unter Verwendung von CROSS APPLY in zwei Teile aufzuteilen.

DECLARE 
@StartDate DATE = '1/1/2017', 
@EndDate DATE = '3/1/2017'; 

WITH 
CTE 
AS 
(
    SELECT 
     DENSE_RANK() OVER (ORDER BY c.socialSecurityNumber) AS [SSNRanking] , 
     ROW_NUMBER() OVER (PARTITION BY c.socialSecurityNumber ORDER BY c.socialSecurityNumber) AS [RowNumb] , 
     c.socialSecurityNumber AS [SSN], 
     c.id AS [CustomerID] , 
     c.firstName AS [FirstName] ,  
     c.lastName AS [lastName] , 
     c.birthDate [birthdate] , 
     c.createDate AS [CreateDate] , 
     c2.socialSecurityNumber AS [DupSSN] , 
     c2.id AS [DupCustomerID] , 
     c2.firstName AS [DupFirstName] , 
     c2.lastName AS [DupLastName] , 
     c2.birthDate AS [DupBirthDate] , 
     c2.createDate AS [DupCreateDate] 
    FROM  
     dbo.Customers AS [c] 
     INNER JOIN dbo.Customers AS [c2] ON (SUBSTRING(c.socialSecurityNumber,6,4) = SUBSTRING(c2.socialSecurityNumber,6,4) AND c.birthDate = c2.birthDate AND c.lastName = c2.lastName AND c.id <> c2.id) 
     LEFT JOIN dbo.CustomerAddresses AS [CA] ON c.id = CA.customerID    
     LEFT JOIN dbo.Common_Orders AS [co] ON co.customerID = c.id 
    WHERE 
     c.customerStatusTypeID <> 'M' 
     AND C2.customerStatusTypeID <> 'M' 
     AND c.mergedTo IS NULL 
     AND c2.mergedTo IS NULL 
     AND CAST(co.orderDate AS DATE) >= @StartDate 
     AND CAST(co.orderDate AS DATE) <= @EndDate 
     AND c.id = 1234439 
    GROUP BY 
     c.socialSecurityNumber , 
     c.id , 
     c.firstName , 
     c.lastName , 
     c.birthDate ,  
     c.createDate , 
     c2.socialSecurityNumber , 
     c2.id , 
     c2.firstName ,   
     c2.lastName , 
     c2.birthDate , 
     c2.createDate 
) 
SELECT 
    CA.SSNRanking 
    ,CA.RowNumb 
    ,CA.SSN 
    ,CA.CustomerID 
    ,CA.FirstName 
    ,CA.lastName 
    ,CA.birthdate 
    ,CA.CreateDate 
FROM 
    CTE 
    CROSS APPLY 
    (
     VALUES 
     (CTE.SSNRanking, CTE.RowNumb, CTE.SSN, CTE.CustomerID, CTE.FirstName, CTE.lastName, CTE.birthdate, CTE.CreateDate), 
     (CTE.SSNRanking, CTE.RowNumb, CTE.DupSSN, CTE.DupCustomerID, CTE.DupFirstName, CTE.DuplastName, CTE.Dupbirthdate, CTE.DupCreateDate) 
    ) AS CA(SSNRanking, RowNumb, SSN, CustomerID, FirstName, lastName, birthdate, CreateDate) 
ORDER BY CAST(CA.SSN AS INT) ASC; 

By the way,

ROW_NUMBER() OVER (PARTITION BY ColumnA ORDER BY ColumnA) 

macht keinen Sinn, wenn man von der gleichen Spalte partitionieren und Ordnung. Ich bin mir nicht sicher, was Sie dort erreichen wollen.

+1

Schön - ich mag diese Lösung. CROSS APPLY ist eines der Dinge, die ich noch nie benutzt habe oder die ich wirklich kenne. Aber das läuft schnell und die Daten sehen gut aus, wie ich es mir erhofft hatte. Und soweit es die ROW_NUMBER betrifft, glaube ich, dass ich es einfach gemacht habe, zu sehen, wann ein SSN zurückgesetzt wurde. Vielen Dank! – MISNole

+0

Ich schätze die Antwort Vlad - ich glaube, das ist fast wo ich brauche die Abfrage zu sein und eine andere Frage, wenn Sie Lust haben, mehr Rep zu verdienen: http://stackoverflow.com/questions/43132297/cross-apply-creating- additional-records – MISNole

+0

@MISNole, tut mir leid, Daten zu bereinigen/Dubletten zu finden ist normalerweise unordentlich und schwierig. Ich glaube nicht, dass es eine Abfrage geben kann, die alle Fälle abdeckt. –

Verwandte Themen