2010-01-16 78 views
129

我想比較兩個表,SQL Server來驗證一些數據。我想從兩個表中返回數據都在一個或另一箇中的所有行。本質上,我想顯示所有的差異。我需要檢查三個數據,FirstName,LastName和Product。SQL查詢返回兩個表之間的差異

我對SQL相當陌生,看起來好像很多我找到的解決方案都是複雜化的東西。我不必擔心NULL。

我開始通過嘗試這樣的:

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

我無法採取這一進一步雖然。

謝謝!

編輯:

基於由@treaschf答案我一直在嘗試使用下面的查詢的變化:

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) 

但我一直得到0的結果回來,當我知道有在td中至少有一行不在d中。

編輯:

好的,我想我想通了。至少在幾分鐘的測試中,它似乎工作得很好。

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]))) 

這基本上是要告訴我什麼是在是在我的實際數據我的測試數據。對於我需要做的事情,這是完全正確的。

+3

下面的例子比這個例子快100倍。 – 2014-01-21 04:42:36

+0

有人可以確認這是否有效?在我的結尾不起作用,如果沒有在任何地方使用「d」,也沒有看到「AS d」這一點,那麼在那裏可能有錯誤嗎? – 2017-03-17 02:48:05

回答

139

如果你有表AB,都與科拉姆C,這裏有記錄,這是目前在表A,但不是在B

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

要獲得所有與單個查詢的不同,一個完整的連接必須使用,就像這樣:

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

你需要在這種情況下知道的是,當一個記錄可以在A找到,但不是在比來自B的列將爲NULL,並且類似地,對於出現在B而不是A中的那些列,來自A的列將爲空。

+0

我很難得到這個工作權利,請參閱我最近的編輯頂部。 – Casey 2010-01-16 16:42:19

+0

問題可能是您無法使用'='與空值進行比較。 (或者至少當SET ANSI_NULLS爲ON時。)您必須說:值IS NULL或值IS NOT NULL。 – treaschf 2010-01-16 17:17:45

+0

我將此標記爲我使用的答案,因爲通過這種方式,我可以輕鬆地做一些其他事情,我不得不稍後再做。 – Casey 2010-01-30 23:38:03

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

+1:這是明智的方式SQL Server 2005+。 – RedFilter 2010-01-16 19:44:01

+0

*(添加了子查詢缺失的別名。)* – RedFilter 2010-01-16 19:48:49

+0

我使用它得到錯誤。我從兩個不同的數據庫中拉出兩張桌子 – 2011-07-20 19:05:11

2

試試這個:

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]) 

更易於閱讀。

34

我知道這可能不是一個流行的答案,但我同意@Randy Minder在需要更復雜的比較時使用第三方工具。

這裏的具體情況很容易,在這種情況下,這種工具不是必需的,但如果在兩臺服務器上引入更多的列,數據庫,更復雜的比較標準等,這可能會變得很複雜。

有很多這些工具,如ApexSQL Data DiffQuest Toad,您可以隨時在試用模式下使用它們來完成工作。

+0

FOSS與數據庫無關的解決方案的一個示例,可與來自各種數據庫或文件系統的任何表格數據源一起使用[Diffkit](http://www.diffkit.org/)。 – wwmbes 2017-02-03 09:17:46

+0

微軟還有一個SQL Server'tablediff'命令行實用程序,稱爲[here](https://www.mssqltips.com/sqlservertip/1073/sql-server-tablediff-command-line-utility/)。 – wwmbes 2017-02-03 13:44:54

4

如果你想獲得的列值是不同的,你可以使用實體 - 屬性 - 值模型:

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

謝謝,我已經使這個代碼有點動態。它現在允許你通過兩個表,你想比較... http://thitos.blogspot.com/2014/03/compare-data-from-two-tables.html – Thato 2014-03-11 12:37:25

+0

工作就像一個魅力只是差異我想要。謝謝 – TypingPanda 2016-09-22 02:10:26

1

對於一個簡單的煙霧測試,你你想確保兩個表匹配w/out擔心列名稱:

--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 

您可以輕鬆編寫一個存儲過程來比較一批表。

0

存在與左連接相關的性能問題以及與大數據的完全連接。

在我看來,這是最好的解決辦法:

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

這將這樣的伎倆,用Tiago的解決方案,回報‘源’表中有相似也。

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 

結果將包含表之間的差異,在_tabloc列中您將有表引用。

4

爲了讓兩個表之間的所有差異,你可以使用像我這個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

上@erikkallen回答簡單的變化,顯示該表中的行存在於:

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