2010-01-16 13 views
129

Sto provando a confrontare due tabelle, SQL Server, per verificare alcuni dati. Voglio restituire tutte le righe da entrambe le tabelle in cui i dati sono nell'uno o nell'altro. In sostanza, voglio mostrare tutte le discrepanze. Ho bisogno di controllare tre pezzi di dati in questo modo, FirstName, LastName e Product.query sql per restituire le differenze tra due tabelle

Sono abbastanza nuovo per SQL e sembra che molte delle soluzioni che trovo siano troppo complicate. Non devo preoccuparmi dei NULL.

ho iniziato cercando qualcosa di simile:

SELECT DISTINCT [First Name], [Last Name], [Product Name] FROM [Temp Test Data] 
WHERE ([First Name] NOT IN (SELECT [First Name] 
FROM [Real Data])) 

Sto avendo difficoltà a prendere questo ulteriore però.

Grazie!

EDIT:

sulla base della risposta da @treaschf Ho cercato di utilizzare una variante della seguente query:

SELECT td.[First Name], td.[Last Name], td.[Product Name] 
FROM [Temp Test Data] td FULL OUTER JOIN [Data] AS d 
ON td.[First Name] = d.[First Name] AND td.[Last Name] = d.[Last Name] 
WHERE (d.[First Name] = NULL) AND (d.[Last Name] = NULL) 

Ma io continuo a ricevere 0 risultati indietro, quando so che c'è è almeno una riga in td che non è in d.

EDIT:

Ok, penso che ho capito. Almeno nei miei pochi minuti di test sembra funzionare abbastanza bene.

SELECT [First Name], [Last Name] 
FROM [Temp Test Data] AS td 
WHERE (NOT EXISTS 
     (SELECT [First Name], [Last Name] 
     FROM [Data] AS d 
     WHERE ([First Name] = td.[First Name]) OR ([Last Name] = td.[Last Name]))) 

questo è fondamentalmente sta per dirmi che cosa è nel mio dati di test che non è nei miei dati reali. Che è completamente bene per quello che devo fare.

+3

L'esempio EXCEPT di seguito è circa 100 volte più veloce di questo. –

+0

qualcuno può confermare se funziona? non funziona sulla mia parte, inoltre non vedo il punto di "AS d" se "d" non è usato da nessuna parte, potrebbe esserci un errore da qualche parte? –

risposta

139

SE avete tabelle A e B, entrambe con Colum C, qui ci sono le registrazioni, che sono presenti nella tabella A ma non in B:

SELECT A.* 
FROM A 
    LEFT JOIN B ON (A.C = B.C) 
WHERE B.C IS NULL 

per ottenere tutte le differenze con una singola query, una full join deve essere utilizzato, in questo modo:

SELECT A.*, B.* 
FROM A 
    FULL JOIN B ON (A.C = B.C) 
WHERE A.C IS NULL OR B.C IS NULL 

quello che dovete sapere in questo caso è, che quando un record può essere trovato in A, ma non in B, rispetto alle colonne che provengono da B sarà NULL e analogamente per quelle presenti in B e non in A, le colonne da A saranno nulle.

+0

Ho problemi a funzionare correttamente, vedere la mia recente modifica in alto. – Casey

+0

Il problema potrebbe essere che non è possibile confrontare un valore con null usando '='. (O almeno quando SET ANSI_NULLS è ON.) È necessario dire: valore IS NULL o valore IS NOT NULL. – treaschf

+0

Sto contrassegnando questo come la risposta che ho usato perché in questo modo sono stato in grado di fare facilmente alcune altre cose che ho dovuto in seguito. – Casey

180
( SELECT * FROM table1 
    EXCEPT 
    SELECT * FROM table2) 
UNION ALL 
( SELECT * FROM table2 
    EXCEPT 
    SELECT * FROM table1) 
+0

+1: questo è il modo ragionevole per SQL Server 2005+. – RedFilter

+0

* (Aggiunto alias mancanti per sottoquery.) * – RedFilter

+0

Ricevo errore durante l'utilizzo. Sto tirando i due tavoli da due database diversi –

2

Prova questo:

SELECT 
    [First Name], [Last Name] 
FROM 
    [Temp Test Data] AS td EXCEPTION JOIN [Data] AS d ON 
     (d.[First Name] = td.[First Name] OR d.[Last Name] = td.[Last Name]) 

Molto più semplice da leggere.

34

So che questa potrebbe non essere una risposta popolare, ma concordo con @Randy Minder sull'utilizzo di strumenti di terze parti quando è necessario un confronto più complesso.

Questo caso specifico qui è semplice e in questo caso tali strumenti non sono necessari, ma questo può diventare complesso se si introducono più colonne, database su due server, criteri di confronto più complessi e così via.

Ci sono molti di questi strumenti come ApexSQL Data Diff o Quest Toad e puoi sempre usarli in modalità di prova per portare a termine il lavoro.

+0

Un esempio di una soluzione indipendente dal database FOSS che funziona con qualsiasi sorgente tabellare di dati da vari database o file system è [Diffkit] (http://www.diffkit.org/). – wwmbes

+0

Microsoft ha anche un'utilità della riga di comando 'tablediff' di SQL Server a cui si fa riferimento [qui] (https://www.mssqltips.com/sqlservertip/1073/sql-server-tablediff-command-line-utility/). – wwmbes

4

Se si desidera ottenere che i valori della colonna sono diversi, è possibile utilizzare il modello Entità-attributo-valore:

declare @Data1 xml, @Data2 xml 

select @Data1 = 
(
    select * 
    from (select * from Test1 except select * from Test2) as a 
    for xml raw('Data') 
) 

select @Data2 = 
(
    select * 
    from (select * from Test2 except select * from Test1) as a 
    for xml raw('Data') 
) 

;with CTE1 as (
    select 
     T.C.value('../@ID', 'bigint') as ID, 
     T.C.value('local-name(.)', 'nvarchar(128)') as Name, 
     T.C.value('.', 'nvarchar(max)') as Value 
    from @Data1.nodes('Data/@*') as T(C)  
), CTE2 as (
    select 
     T.C.value('../@ID', 'bigint') as ID, 
     T.C.value('local-name(.)', 'nvarchar(128)') as Name, 
     T.C.value('.', 'nvarchar(max)') as Value 
    from @Data2.nodes('Data/@*') as T(C)  
) 
select 
    isnull(C1.ID, C2.ID) as ID, isnull(C1.Name, C2.Name) as Name, C1.Value as Value1, C2.Value as Value2 
from CTE1 as C1 
    full outer join CTE2 as C2 on C2.ID = C1.ID and C2.Name = C1.Name 
where 
not 
(
    C1.Value is null and C2.Value is null or 
    C1.Value is not null and C2.Value is not null and C1.Value = C2.Value 
) 

SQL FIDDLE EXAMPLE

+0

Grazie, ho reso questo codice un po 'dinamico. Ora consente di passare due tabelle che si desidera confrontare ... http://thitos.blogspot.com/2014/03/compare-data-from-two-tables.html – Thato

+0

Lavoro come un fascino solo il diff Voglio. Grazie – TypingPanda

1

Per un semplice test del fumo dove si sta cercando di garantire la due tabelle corrispondono w/out preoccuparsi di nomi di colonna:

--ensure tables have matching records 
Select count (*) from tbl_A 
Select count (*) from tbl_B 

--create temp table of all records in both tables 
Select * into #demo from tbl_A 
Union All 
Select * from tbl_B 

--Distinct #demo records = Total #demo records/2 = Total tbl_A records = total tbl_B records 
Select distinct * from #demo 

si può facilmente scrivere una procedura negozio per confrontare una serie di tabelle.

0

Esiste un problema di prestazioni relativo al join sinistro e un join completo con dati di grandi dimensioni.

A mio parere questa è la soluzione migliore:

select [First Name], count(1) e from (select * from [Temp Test Data] union all select * from [Temp Test Data 2]) a group by [First Name] having e = 1 
1

Questo farà il trucco, simile con la soluzione, il ritorno 'fonte' Tiago 's tavolo pure.

select [First name], [Last name], max(_tabloc) as _tabloc 
from (
    select [First Name], [Last name], 't1' as _tabloc from table1 
    union all 
    select [First name], [Last name], 't2' as _tabloc from table2 
) v 
group by [Fist Name], [Last name] 
having count(1)=1 

risultato conterrà le differenze tra le tabelle, nella colonna _tabloc avrete riferimento tavolo.

4

Per ottenere tutte le differenze tra due tabelle, è possibile utilizzare come me questa richiesta SQL:

SELECT 'TABLE1-ONLY' AS SRC, T1.* 
FROM (
     SELECT * FROM Table1 
     EXCEPT 
     SELECT * FROM Table2 
    ) AS T1 
UNION ALL 
SELECT 'TABLE2-ONLY' AS SRC, T2.* 
FROM (
     SELECT * FROM Table2 
     EXCEPT 
     SELECT * FROM Table1 
    ) AS T2 
; 
1

variazione semplice sulla risposta @erikkallen che mostra quale tabella la riga è presente in:

( SELECT 'table1' as source, * FROM table1 
    EXCEPT 
    SELECT * FROM table2) 
UNION ALL 
( SELECT 'table2' as source, * FROM table2 
    EXCEPT 
    SELECT * FROM table1) 
Problemi correlati