2011-01-05 4 views
45

У меня 2 таблицы TableA и TableB, которые имеют тот же формат столбец, например обе таблицы TableA и TableB есть столбцыSQL-сравнить данные из двух таблиц

A B C D E F 

где А и В являются первичными ключами.

Как написать SQL, чтобы проверить, что если TableA и TableB, которые имеют одинаковые первичные ключи, содержат точно такое же значение в каждом столбце.

Это означает, что эти две таблицы имеют точно такие же данные.

+0

еще помогает много –

+1

На мой взгляд, этот вопрос заслуживает ответ будет отмечен ... –

ответ

46

Вы должны иметь возможность «MINUS» или «EXCEPT» в зависимости от вкуса SQL, используемого вашей СУБД.

select * from tableA 
minus 
select * from tableB 

Если запрос не возвращает строк, данные будут точно такими же.

+4

Прекрасное предложение. Тем не менее, я думаю, что это может не сработать, если tableB имеет дополнительные строки, поэтому вам может понадобиться сравнить количество строк в дополнение. – jzd

+4

Другой путь. Он не будет работать, если 'tableA' имеет дополнительные строки. Вам понадобится '(A EXCEPT B) INTERSECT (B EXCEPT A)' Я бы предположил, что это будет намного менее эффективно, чем стандартное соединение болота. –

+0

запрос возвращает два набора результатов? – Jerome

14

dietbuddha имеет приятный ответ. В тех случаях, когда у вас нет минуса или за исключением, один вариант, чтобы сделать объединение все между таблицами, группами по всем столбцам и убедитесь, что есть два всего:

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

Я пробовал использовать это (я получил его из [Jeff's SQL Server Blog] (http://weblogs.sqlteam.com/jeffs/archive/2004/11/10/2737.aspx)), но я хотел бы перечислить обе строки из TableA и TableB, чтобы я мог визуально видеть различия в строках. Не могли бы вы объяснить, как это сделать? –

+0

@Agent, это звучит как отдельный вопрос. Я бы предложил его распечатать, чтобы другие увидели его, а не просто комментарий здесь. – jzd

+0

Готово. И сделано. [Сравнение значений двух таблиц и перечисление строк, которые отличаются) (http://stackoverflow.com/questions/6442146/comparing-values-of-2-tables-and-listing-the-rows-that-are-different). Надеюсь, я получу отличные результаты.:) –

0

В MySQL, где "минус" не поддерживается, а также принимая во внимание производительность, это быстро

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

Использование реляционных операторов:

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

Изменить EXCEPT в MINUS для Oracle.

Немного придирчивая точка: вышеупомянутое полагается на приоритет оператора, который, согласно стандарту SQL, зависит от реализации, поэтому YMMV. Она работает для SQL Server, для которого старшинства:

  1. Выражения в скобках
  2. INTERSECT
  3. EXCEPT и UNION вычисляются слева направо.
+0

Для Oracle вам нужно использовать круглые скобки вокруг UNION, круглые скобки вокруг INTERSECT и (как отмечено) заменить EXCEPT на MINUS. НТН. –

1

только COMPLET, прок хранятся с использованием, кроме способа сравнить 2 таблицы и дать результат в одной таблице со статусом 3 ошибки, ADD, DEL, GAP таблица должна иметь тот же ПК, объявляются 2 таблицы и поля для сравнения 1 или как таблицы

Просто используйте как этот ps_TableGap 'tbl1', 'Tbl2', 'FLD1, fld2, fld3', 'fld4'fld5'fld6' (опция)

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

Принимая сценарий из onedaywhenwhen, я изменил его, чтобы также показать, из какой таблицы поступает каждая запись.

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

Усиление ответа диетыbuddha ...

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

Вернется все идентификаторы, которые являются одинаковыми в обеих таблицах. Чтобы получить разницу, измените 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]) 

Результат пуст, но источники разные!

Но:

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

работы.

0

У меня была эта же проблема в SQL Server и написала этот сценарий T-SQL для автоматизации процесса (на самом деле это версия с опущенной версией, моя написала все различия в одной таблице для упрощения отчетности).

Обновите «MyTable» и «MyOtherTable» на имена таблиц, которые вы хотите сравнить.

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

Я написал это, чтобы сравнить результаты довольно неприятного вида, перенесенного с Oracle на SQL Server. Он создает пару временных таблиц, #DataVariances и #SchemaVariances, с различиями в (как вы уже догадались) данными в таблицах и схемой самих таблиц.

Он требует, чтобы обе таблицы имели первичный ключ, но вы могли бы поместить его в tempdb с помощью столбца идентификации, если исходные таблицы не имеют его.

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

Альтернатива, расширенный запрос на основе ответа на dietbuddha & IanMc. В запросе содержится описание, чтобы помочь показать, где строки существуют и отсутствуют. (NB: для 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 
) 
Смежные вопросы