2017-03-29 3 views
1

J'essaie d'identifier les clients potentiels en double dans ma base de données en fonction des 4 derniers numéros de sécurité sociale, nom de famille et date de naissance. La procédure stockée que j'ai écrite identifie les doublons potentiels mais les répertorie en une seule ligne - j'essaie de les diviser en lignes séparées pour des raisons de rapport.Dupliquer les potentiels potentiels en différentes lignes

Mon T-SQL ressemble à:

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; 

Et mon jeu de données ressemble à:

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 

Dans ce cas particulier, j'ai deux utilisateurs avec le même dernier 4 du SSN, même nom de famille et même date de naissance - mais des prénoms différents.

Comment puis-je faire apparaître ces deux enregistrements sur des lignes distinctes? Idéalement, je voudrais voir:

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 

Mais je ne suis pas sûr comment je peux accomplir ceci en se joignant à la même table. Suggestions?

Je crée un lien vers un script qui crée les deux tables en question et insère des données d'exemple. Espérons que cela soit acceptable: SQL Script

+0

Pouvez-vous fournir des définitions de table et des exemples de données? –

+0

Bien sûr, vous avez besoin de définitions de tables pour les tables sous-jacentes ou la définition de la table de jeu de résultats fonctionne-t-elle? – MISNole

+0

les tables sous-jacentes mais pas besoin de toutes les colonnes juste assez pour répliquer votre problème et pour trouver une solution –

Répondre

1

Ceci est appelé "unpivot". Vous pouvez utiliser l'opérateur UNPIVOT, mais je préfère utiliser CROSS APPLY ... VALUES.

J'envelopperai votre requête dans CTE sans la regarder en détail et diviser chaque ligne en deux en utilisant CROSS APPLY.

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; 

Par ailleurs,

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

n'a pas de sens lorsque vous partitionner et de l'ordre par la même colonne. Je ne suis pas sûr de ce que vous voulez réaliser là-bas.

+1

Nice - J'aime cette solution. CROSS APPLY est l'une de ces choses que je n'ai jamais utilisé ou que je ne savais vraiment pas utiliser. Mais cela va vite et les données semblent bonnes, comme j'espérais. Et en ce qui concerne le ROW_NUMBER, je crois que j'étais juste en train de me rendre plus facile de voir quand un SSN a été réinitialisé. Merci! – MISNole

+0

J'apprécie la réponse Vlad - Je crois que c'est presque là où j'ai besoin de la requête pour être et posté une autre question si vous avez envie de gagner plus de rep: http://stackoverflow.com/questions/43132297/cross-apply-creating- additional-records – MISNole

+0

@MISNole, désolé, nettoyer les données/trouver des doublons est généralement compliqué et difficile. Je ne pense pas qu'il puisse y avoir une requête qui couvre tous les cas. –