2011-01-05 19 views
45

Ich habe 2 Tabellen TableA und TableB die dasselbe Format der Spalte zum Beispiel haben beide Tabellen TableA und TableB haben SpaltenSQL vergleichen Daten aus zwei Tabellen

A B C D E F 

wobei A und B die Primärschlüssel sind.

Wie schreibe ich SQL, um zu überprüfen, ob TableA und TableB die gleichen Primärschlüssel enthalten genau den gleichen Wert in jeder Spalte.

Dies bedeutet, dass diese beiden Tabellen genau die gleichen Daten haben.

+0

noch hilft es, viel –

+1

Meiner Meinung nach, verdient diese Frage eine Antwort zu markierende ... –

Antwort

46

Sie sollten in der Lage sein, "MINUS" oder "EXCEPT" abhängig von der von Ihrem DBMS verwendeten SQL-Variante zu verwenden.

select * from tableA 
minus 
select * from tableB 

Wenn die Abfrage keine Zeilen zurückgibt, sind die Daten identisch.

+4

Excellent Vorschlag. Ich denke jedoch, dass dies möglicherweise nicht funktioniert, wenn Tabelle B eine zusätzliche Zeile (n) enthält, sodass Sie die Zeilenanzahl möglicherweise zusätzlich vergleichen möchten. – jzd

+4

Anders herum. Es funktioniert nicht, wenn 'tableA' zusätzliche Zeilen hat. Sie würden '(A EXCEPT B) INTERSECT (B EXCEPT A)' Ich würde vermuten, das wäre viel weniger effizient als ein Moor Standard Join. –

+0

die Abfrage gibt zwei Ergebnismengen zurück ?? – Jerome

14

dietbuddha hat eine nette Antwort. In Fällen, in denen Sie keine MINUS haben oder EXCEPT, eine Möglichkeit ist, eine Vereinigung aller zwischen den Tischen, Gruppe mit allen Spalten zu tun und es sicherstellen, dass zwei von allem ist:

SELECT col1, col2, col3 
FROM 
(SELECT * FROM tableA 
UNION ALL 
SELECT * FROM tableB) data 
GROUP BY col1, col2, col3 
HAVING count(*)!=2 
+0

Ich habe versucht, dies zu verwenden (ich habe es aus [Jeff SQL Server Blog] (http://weblogs.sqlteam.com/jeffs/archive/2004/11/10/2737.aspx)), aber ich möchte auflisten beide Zeilen von TableA und TableB, damit ich die Unterschiede in den Zeilen visuell sehen kann. Würde es Ihnen etwas ausmachen, das zu erklären? –

+0

@Agent, das klingt wie eine separate Frage. Ich würde vorschlagen, es aufzulisten, damit andere es sehen, anstatt nur einen Kommentar hier. – jzd

+0

Fertig. Und fertig. [Vergleiche Werte von 2 Tabellen und listet die Zeilen auf, die unterschiedlich sind] (http://stackoverflow.com/questions/6442146/comparing-values-of-2-tables-and-listing-the-rows-that-are-different). Hoffentlich bekomme ich tolle Ergebnisse.:) –

0

in MySQL, wo „minus“ nicht unterstützt wird, und die Leistung berücksichtigt, ist dies eine schnelle

query: 
SELECT 
t1.id, 
t1.id 
FROM t1 inner join t2 using (id) where concat(t1.C, t1.D, ...)<>concat(t2.C, t2.D, ...) 
31

relationalen Operatoren:

SELECT * FROM TableA 
UNION 
SELECT * FROM TableB 
EXCEPT 
SELECT * FROM TableA 
INTERSECT 
SELECT * FROM TableB; 

ändern EXCEPT-MINUS für Oracle.

Etwas pingeliger Punkt: Obiges hängt von der Rangfolge des Operators ab, die gemäß dem SQL-Standard implementierungsabhängig ist, also YMMV. Es funktioniert für SQL Server, für die die Priorität ist:

  1. Ausdrücke in Klammern
  2. INTERSECT
  3. EXCEPT und UNION von links nach rechts ausgewertet.
+0

Für Oracle müssen Sie Klammern um die UNION, Klammern um die INTERSECT herum verwenden und (wie angegeben) EXCEPT durch MINUS ersetzen. HTH. –

1

nur complet, ein proc außer Methode gespeichert unter Verwendung von 2 Tabellen zu vergleichen und Ergebnis in derselben Tabelle mit 3 Fehler-Status geben, ADD, DEL, GAP Tisch gleiche PK haben muß, erklären Sie die 2 Tabellen und Felder vergleichen

von 1 oder beide Tabellen verwenden

wie diese ps_TableGap 'TBL1', 'TBL2', 'FLD1, FLD2, Fld3', 'fld4'fld5'fld6' (optional)

/****** Object: StoredProcedure [dbo].[ps_TableGap] Script Date: 10/03/2013 16:03:44 ******/ 
SET ANSI_NULLS ON 
GO 
SET QUOTED_IDENTIFIER ON 
GO 

-- ============================================= 
-- Author:  Arnaud ALLAVENA 
-- Create date: 03.10.2013 
-- Description: Compare tables 
-- ============================================= 
create PROCEDURE [dbo].[ps_TableGap] 
    -- Add the parameters for the stored procedure here 
    @Tbl1 as varchar(100),@Tbl2 as varchar(100),@Fld1 as varchar(1000), @Fld2 as varchar(1000)= '' 
AS 
BEGIN 
    -- SET NOCOUNT ON added to prevent extra result sets from 
    -- interfering with SELECT statements. 

    SET NOCOUNT ON; 
--Variables 
[email protected] = table 1 
[email protected] = table 2 
[email protected] = Fields to compare from table 1 
[email protected] Fields to compare from table 2 
Declare @SQL varchar(8000)= '' --SQL statements 
Declare @nLoop int = 1 --loop counter 
Declare @Pk varchar(1000)= '' --primary key(s) 
Declare @Pk1 varchar(1000)= '' --first field of primary key 
declare @strTmp varchar(50) = '' --returns value in Pk determination 
declare @FldTmp varchar (1000) = '' --temporarily fields for alias calculation 

--If @Fld2 empty we take @Fld1 
--fields rules: fields to be compare must be in same order and type - always returns Gap 
If @Fld2 = '' Set @Fld2 = @Fld1 

--Change @Fld2 with Alias prefix xxx become _xxx 
while charindex(',',@Fld2)>0 
begin 
    Set @FldTmp = @FldTmp + (select substring(@Fld2,1,charindex(',',@Fld2)-1) + ' as _' + substring(@Fld2,1,charindex(',',@Fld2)-1) + ',') 
    Set @Fld2 = (select ltrim(right(@Fld2,len(@Fld2)-charindex(',',@Fld2)))) 
end 
Set @FldTmp = @FldTmp + @Fld2 + ' as _' + @Fld2 
Set @Fld2 = @FldTmp 

--Determinate primary key jointure 
--rule: same pk in both tables 
Set @nLoop = 1 
Set @SQL = 'Declare crsr cursor for select COLUMN_NAME from INFORMATION_SCHEMA.KEY_COLUMN_USAGE where TABLE_NAME = ''' 
+ @Tbl1 + ''' or TABLE_SCHEMA + ''.'' + TABLE_NAME = ''' + @Tbl1 + ''' or TABLE_CATALOG + ''.'' + TABLE_SCHEMA + ''.'' + TABLE_NAME = ''' + @Tbl1 
+ ''' order by ORDINAL_POSITION' 
exec(@SQL) 
open crsr 
fetch next from crsr into @strTmp 
while @@fetch_status = 0 
begin 
    if @nLoop = 1 
    begin 
     Set @Pk = 's.' + @strTmp + ' = b._' + @strTmp 
     Set @Pk1 = @strTmp 
     set @nLoop = @nLoop + 1 
    end 
    Else 
    Set @Pk = @Pk + ' and s.' + @strTmp + ' = b._' + @strTmp 
fetch next from crsr into @strTmp 

end 
close crsr 
deallocate crsr 

--SQL statement build 
set @SQL = 'select case when s.' + @Pk1 + ' is null then ''Del'' when b._' + @Pk1 + ' is null then ''Add'' else ''Gap'' end as TypErr, ''' 
set @SQL = @SQL + @Tbl1 +''' as Tbl1, s.*, ''' + @Tbl2 +''' as Tbl2 ,b.* from (Select ' + @Fld1 + ' from ' + @Tbl1 
set @SQL = @SQL + ' EXCEPT SELECT ' + @Fld2 + ' from ' + @Tbl2 + ')s full join (Select ' + @Fld2 + ' from ' + @Tbl2 
set @SQL = @SQL + ' EXCEPT SELECT ' + @Fld1 + ' from ' + @Tbl1 +')b on '+ @Pk 

--Run SQL statement 
Exec(@SQL) 
END 
3

Ich nahm das Skript von onedaywhen, änderte es, um auch zu zeigen, aus welcher Tabelle jeder Eintrag stammt.

DECLARE @table1 NVARCHAR(80)= 'table 1 name' 
DECLARE @table2 NVARCHAR(80)= 'table 2 name' 
DECLARE @sql NVARCHAR (1000) 

SET @sql = 
' 
SELECT ''' + @table1 + ''' AS table_name,* FROM 
(
SELECT * FROM ' + @table1 + ' 
EXCEPT 
SELECT * FROM ' + @table2 + ' 
) x 

UNION 

SELECT ''' + @table2 + ''' AS table_name,* FROM 
(
SELECT * FROM ' + @table2 + ' 
EXCEPT 
SELECT * FROM ' + @table1 + ' 
) y 
' 

EXEC sp_executesql @stmt = @sql 
0

Verbesserung zu diätbuddhas Antwort ...

select * from 
(
    select * from tableA 
    minus 
    select * from tableB 
) 
union all 
select * from 
(
    select * from tableB 
    minus 
    select * from tableA 
) 
5
SELECT c.ID 
FROM clients c 
WHERE EXISTS(SELECT c2.ID 
FROM clients2 c2 
WHERE c2.ID = c.ID); 

Werden alle IDs zurück, die das gleiche in beiden Tabellen sind. Um die Unterschiede zu erhalten, ändern Sie EXISTS auf NOT EXISTS.

1
SELECT unnest(ARRAY[1,2,2,3,3]) 
    EXCEPT 
    SELECT unnest(ARRAY[1,1,2,3,3]) 
UNION 
    SELECT unnest(ARRAY[1,1,2,3,3]) 
    EXCEPT 
    SELECT unnest(ARRAY[1,2,2,3,3]) 

Ergebnis ist null, aber Quellen sind unterschiedlich!

Aber:

(
    SELECT unnest(ARRAY[1,2,2,3]) 
    EXCEPT ALL 
    SELECT unnest(ARRAY[2,1,2,3]) 
) 
UNION 
(
    SELECT unnest(ARRAY[2,1,2,3]) 
    EXCEPT ALL 
    SELECT unnest(ARRAY[1,2,2,3]) 
) 

funktioniert.

0

Ich hatte das gleiche Problem in SQL Server und schrieb dieses T-SQL-Skript, um den Prozess zu automatisieren (eigentlich ist dies die verwässerte Version, meins schrieb alle Diff in eine einzige Tabelle für die einfache Berichterstattung).

Aktualisieren Sie "MyTable" und "MyOtherTable" auf die Namen der Tabellen, die Sie vergleichen möchten.

DECLARE @ColName varchar(100) 
DECLARE @Table1 varchar(100) = 'MyTable' 
DECLARE @Table2 varchar(100) = 'MyOtherTable' 


IF (OBJECT_ID('tempdb..#col') IS NOT NULL) DROP TABLE #col 
SELECT IDENTITY(INT, 1, 1) RowNum , c.name 
INTO #col 
FROM SYS.Objects o 
     JOIN SYS.columns c on o.object_id = c.object_id 
WHERE o.name = @Table1 AND NOT c.Name IN ('List','Columns','YouWantToIgnore') 

DECLARE @Counter INT = (SELECT MAX(RowNum) FROM #col) 

    WHILE @Counter > 0 

     BEGIN 
      SET @ColName = (SELECT name FROM #Col WHERE RowNum= @Counter) 
       EXEC ('SELECT t1.Identifier 
         ,t1.'[email protected]+' AS '[email protected][email protected]+' 
         ,t2.'[email protected]+' AS '[email protected][email protected]+' 
       FROM '[email protected]+' t1 
         LEFT JOIN '[email protected]+' t2 ON t1.Identifier = t2.Identifier 
       WHERE t1.'[email protected]+' <> t2.'[email protected]) 
      SET @Counter = @Counter - 1 
     END 
0

Ich schrieb dies die Ergebnisse eines ziemlich bösen Blicks zu vergleichen, die ich von Oracle zu SQL Server portierte. Es erstellt ein Paar temporäre Tabellen, #DataVariances und #SchemaVariances, mit Unterschieden in (Sie haben es erraten) die Daten in den Tabellen und das Schema der Tabellen selbst.

Es erfordert beide Tabellen einen Primärschlüssel, aber Sie könnten es in Tempdb mit einer Identitätsspalte löschen, wenn die Quelltabellen keinen haben.

declare @TableA_ThreePartName nvarchar(max) = '' 
declare @TableB_ThreePartName nvarchar(max) = '' 
declare @KeyName nvarchar(max) = '' 

/*********************************************************************************************** 

    Script to compare two tables and return differneces in schema and data. 

    Author: Devin Lamothe  2017-08-11 

***********************************************************************************************/ 
set nocount on 

-- Split three part name into database/schema/table 
declare @Database_A nvarchar(max) = (
    select left(@TableA_ThreePartName,charindex('.',@TableA_ThreePartName) - 1)) 
declare @Table_A nvarchar(max) = (
    select right(@TableA_ThreePartName,len(@TableA_ThreePartName) - charindex('.',@TableA_ThreePartName,len(@Database_A) + 2))) 
declare @Schema_A nvarchar(max) = (
    select replace(replace(@TableA_ThreePartName,@Database_A + '.',''),'.' + @Table_A,'')) 

declare @Database_B nvarchar(max) = (
    select left(@TableB_ThreePartName,charindex('.',@TableB_ThreePartName) - 1)) 
declare @Table_B nvarchar(max) = (
    select right(@TableB_ThreePartName,len(@TableB_ThreePartName) - charindex('.',@TableB_ThreePartName,len(@Database_B) + 2))) 
declare @Schema_B nvarchar(max) = (
    select replace(replace(@TableB_ThreePartName,@Database_B + '.',''),'.' + @Table_B,'')) 

-- Get schema for both tables 
declare @GetTableADetails nvarchar(max) = ' 
    use [' + @Database_A +'] 
     select COLUMN_NAME 
      , DATA_TYPE 
      from INFORMATION_SCHEMA.COLUMNS 
     where TABLE_NAME = ''' + @Table_A + ''' 
      and TABLE_SCHEMA = ''' + @Schema_A + ''' 
    ' 
create table #Table_A_Details (
    ColumnName nvarchar(max) 
, DataType nvarchar(max) 
) 
insert into #Table_A_Details 
exec (@GetTableADetails) 

declare @GetTableBDetails nvarchar(max) = ' 
    use [' + @Database_B +'] 
     select COLUMN_NAME 
      , DATA_TYPE 
      from INFORMATION_SCHEMA.COLUMNS 
     where TABLE_NAME = ''' + @Table_B + ''' 
      and TABLE_SCHEMA = ''' + @Schema_B + ''' 
    ' 
create table #Table_B_Details (
    ColumnName nvarchar(max) 
, DataType nvarchar(max) 
) 
insert into #Table_B_Details 
exec (@GetTableBDetails) 


-- Get differences in table schema 
      select ROW_NUMBER() over (order by 
         a.ColumnName 
        , b.ColumnName) as RowKey 
       , a.ColumnName as A_ColumnName 
       , a.DataType as A_DataType 
       , b.ColumnName as B_ColumnName 
       , b.DataType as B_DataType 
       into #FieldList 
       from #Table_A_Details a 
    full outer join #Table_B_Details b 
       on a.ColumnName = b.ColumnName 
      where a.ColumnName is null 
       or b.ColumnName is null 
       or a.DataType <> b.DataType 

     drop table #Table_A_Details 
     drop table #Table_B_Details 

      select coalesce(A_ColumnName,B_ColumnName) as ColumnName 
       , A_DataType 
       , B_DataType 
       into #SchemaVariances 
       from #FieldList 

-- Get differences in table data 
declare @LastColumn int = (select max(RowKey) from #FieldList) 
declare @RowNumber int = 1 
declare @ThisField nvarchar(max) 
declare @TestSql nvarchar(max) 



create table #DataVariances (
    TableKey   nvarchar(max) 
, FieldName   nvarchar(max) 
, TableA_Value  nvarchar(max) 
, TableB_Value  nvarchar(max) 
) 

delete from #FieldList where A_DataType in ('varbinary','image') or B_DataType in ('varbinary','image') 

while @RowNumber <= @LastColumn begin 
    set @TestSql = ' 
     select coalesce(a.[' + @KeyName + '],b.[' + @KeyName + ']) as TableKey 
      , ''' + @ThisField + ''' as FieldName 
      , a.[' + @ThisField + '] as [TableA_Value] 
      , b.[' + @ThisField + '] as [TableB_Value] 
      from [' + @Database_A + '].[' + @Schema_A + '].[' + @Table_A + '] a 
    inner join [' + @Database_B + '].[' + @Schema_B + '].[' + @Table_B + '] b 
      on a.[' + @KeyName + '] = b.[' + @KeyName + '] 
     where ltrim(rtrim(a.[' + @ThisField + '])) <> ltrim(rtrim(b.[' + @ThisField + '])) 
      or (a.[' + @ThisField + '] is null and b.[' + @ThisField + '] is not null) 
      or (a.[' + @ThisField + '] is not null and b.[' + @ThisField + '] is null) 
' 

insert into #DataVariances 
exec (@TestSql) 

set @RowNumber = @RowNumber + 1 
set @ThisField = (select coalesce(A_ColumnName,B_ColumnName) from #FieldList a where RowKey = @RowNumber) 

end 

drop table #FieldList 

print 'Query complete. Select from #DataVariances to verify data integrity or #SchemaVariances to verify schemas match. Data types varbinary and image are not checked.' 
1

Eine Alternative, verbesserte Abfrage basierend auf Antwort von dietbuddha & IanMc. Die Abfrage enthält eine Beschreibung, um hilfreich zu zeigen, wo Zeilen vorhanden sind und fehlen. (NB: für SQL Server)

(
    select 'InTableA_NoMatchInTableB' as Msg, * from tableA 
    except 
    select 'InTableA_NoMatchInTableB' , * from tableB 
) 
union all 
(
    select 'InTableB_NoMatchInTableA' as Msg, * from tableB 
    except 
    select 'InTableB_NNoMatchInTableA' ,* from tableA 
) 
Verwandte Themen