web-dev-qa-db-ja.com

2つのテーブル間の違いを返すためのSQLクエリ

いくつかのデータを検証するために、2つのテーブル、SQL Serverを比較しようとしています。データがどちらか一方にある場合、両方のテーブルからすべての行を返します。本質的に、私はすべての食い違いを見せたいのです。その際には、FirstName、LastName、Productの3つのデータをチェックする必要があります。

私は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)

しかし、dにはない少なくとも1つの行がtdにあることがわかっている場合は、0の結果が返され続けます。

編集:

わかりました、私はそれを考え出したと思います。少なくとも私の数分間のテストでは十分にうまくいくようです。

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

これは基本的に、私の実際のデータではnotである私のテストデータに何があるのか​​を教えてくれます。これは私がする必要があることのために全く問題ありません。

162
Casey

両方ともcolum Aを持つテーブルBCがある場合、これらのレコードは次のとおりです。テーブル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で見つからない場合、Bから来る列はNULLになり、Bではなく、Aにない列でもそうなることです。 Aの列はNULLになります。

181
treaschf
(   SELECT * FROM table1
    EXCEPT
    SELECT * FROM table2)  
UNION ALL
(   SELECT * FROM table2
    EXCEPT
    SELECT * FROM table1) 
218
erikkallen

私はこれが一般的な答えではないかもしれないことを知っています、しかし私はより複雑な比較が必要なときサードパーティ製のツールを使うことについて@Randy Minderに同意します。

この特定のケースは簡単で、このケースではそのようなツールは必要ありませんが、より多くの列、2つのサーバー上のデータベース、より複雑な比較基準などを導入すると、これは簡単に複雑になります。

ApexSQL Data DiffQuest Toad などのツールが多数あります。そして、あなたは仕事を終わらせるためにいつでもトライアルモードでそれらを使うことができます。

36
Maisie John

2つのテーブル間の違いをすべて取得するには、この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
;
9
bilelovitch

どの列値が異なるのかを知りたい場合は、Entity-Attribute-Valueモデルを使用できます。

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

4
Roman Pekar

@erikkallen回答の単純なバリエーションで、行がどのテーブルにあるかを示します。

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

エラーが発生した場合

UNION、INTERSECT、またはEXCEPT演算子を使用して組み合わされたすべての照会は、それらのターゲット・リストに同数の式がなければなりません。

それからそれは追加するのを助けるかもしれません

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

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にはテーブル参照があります。

これを試して :

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

読みやすくなりました。

2
Kango_V

単純なスモークテストでは、2つのテーブルが列名を気にせずに一致することを確認します。

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

テーブルのバッチを比較するためのストアドプロシージャを簡単に書くことができます。

1
thomas398

ラージデータとのフルジョインだけでなく、左ジョインにもパフォーマンス上の問題があります。

私の意見では、これが最善の解決策です。

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
0
Tiago Moutinho

私は未来から来ました、あなたは次のようなものを除いて使用できます:

-- DB1..Tb1 have values than DB2..Tb1 not have
Select Col1,Col2,Col3 From DB1..Tb1
except
Select Col1,Col2,Col3 From DB2..Tb1
-- Now we change order
-- DB2..Tb1 have values than DB1..Tb1 not have
Select Col1,Col2,Col3 From DB2..Tb1
except
Select Col1,Col2,Col3 From DB1..Tb1
0
GiovaniSalazar