Saya memiliki 2 tabel TableA
dan TableB
memiliki format kolom yang sama misalnya tabel TableA
dan TableB
kolom
A B C D E F
dimana A dan B adalah kunci utama.
Cara menulis SQL untuk memeriksa apakah TableA
dan TableB
yang memiliki kunci utama yang sama berisi nilai yang persis sama di setiap kolom.
Artinya, kedua tabel ini memiliki data yang sama persis.
tableA
memiliki baris ekstra. Anda akan membutuhkan(A EXCEPT B) INTERSECT (B EXCEPT A)
Saya kira ini akan jauh lebih efisien daripada gabungan standar rawa.Menggunakan operator relasional:
SELECT * FROM TableA UNION SELECT * FROM TableB EXCEPT SELECT * FROM TableA INTERSECT SELECT * FROM TableB;
Ubah
EXCEPT
keMINUS
untuk Oracle.Sedikit pilih-pilih: hal di atas bergantung pada prioritas operator, yang menurut Standar SQL bergantung pada implementasi, jadi YMMV. Ini berfungsi untuk SQL Server, di mana prioritasnya adalah:
INTERSECT
EXCEPT
danUNION
dievaluasi dari kiri ke kanan.sumber
dietbuddha punya jawaban yang bagus. Dalam kasus di mana Anda tidak memiliki MINUS atau KECUALI, salah satu opsi adalah melakukan penyatuan semua tabel, kelompokkan dengan semua kolom dan pastikan semuanya ada dua:
SELECT col1, col2, col3 FROM (SELECT * FROM tableA UNION ALL SELECT * FROM tableB) data GROUP BY col1, col2, col3 HAVING count(*)!=2
sumber
DISTINCT
/GROUP BY
disarankan untuk subkueri di gabungan, untuk memastikan hanya ada satu rekaman per tabel. Jika tidak, TableA dapat memiliki 2 record dan TableB dapat memiliki 0 dan tidak memenuhi kondisi HAVING.SELECT c.ID FROM clients c WHERE EXISTS(SELECT c2.ID FROM clients2 c2 WHERE c2.ID = c.ID);
Akan mengembalikan semua ID yang SAMA di kedua tabel. Untuk mendapatkan perbedaannya, ubah EXISTS menjadi NOT EXISTS.
sumber
Mengambil skrip dari onedaywhen, saya memodifikasinya untuk juga menunjukkan dari tabel mana setiap entri berasal.
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
sumber
hanya untuk menyelesaikan, sebuah proc disimpan menggunakan metode kecuali untuk membandingkan 2 tabel dan memberikan hasil dalam tabel yang sama dengan 3 status kesalahan, TAMBAH, DEL, tabel GAP harus memiliki PK yang sama, Anda menyatakan 2 tabel dan bidang untuk membandingkan 1 atau kedua tabel
Cukup gunakan seperti ini ps_TableGap 'tbl1', 'Tbl2', 'fld1, fld2, fld3', 'fld4'fld5'fld6' (opsional)
/****** 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 --@Tbl1 = table 1 --@Tbl2 = table 2 --@Fld1 = Fields to compare from table 1 --@Fld2 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
sumber
Sumber: Gunakan NATURAL FULL JOIN untuk membandingkan dua tabel dalam SQL oleh Lukas Eder
Pendekatan pintar menggunakan
NATURAL FULL JOIN
untuk mendeteksi baris yang sama / berbeda antara dua tabel.Contoh 1 - bendera status:
SELECT t1.*, t2.*, CASE WHEN t1 IS NULL OR t2 IS NULL THEN 'Not equal' ELSE 'Equal' END FROM t1 NATURAL FULL JOIN t2;
Contoh 2 - memfilter baris
SELECT * FROM (SELECT 't1' AS t1, t1.* FROM t1) t1 NATURAL FULL JOIN (SELECT 't2' AS t2, t2.* FROM t2) t2 WHERE t1 IS NULL OR t2 IS NULL -- show differences --WHERE t1 IS NOT NULL AND t2 IS NOT NULL -- show the same
db <> demo biola
sumber
Peningkatan jawaban dietbuddha ...
select * from ( select * from tableA minus select * from tableB ) union all select * from ( select * from tableB minus select * from tableA )
sumber
Anda dapat menemukan perbedaan 2 tabel menggunakan kombinasi insert all dan full outer join di Oracle. Di sql Anda dapat mengekstrak perbedaan melalui full outer join tetapi tampaknya insert all / first tidak ada di sql! Karenanya, Anda harus menggunakan kueri berikut sebagai gantinya:
select * from A full outer join B on A.pk=B.pk where A.field1!=B.field1 or A.field2!=B.field2 or A.field3!=B.field3 or A.field4!=B.field4 --and A.Date==Date1
Meskipun menggunakan 'OR' di mana klausa tidak disarankan dan biasanya menghasilkan kinerja yang lebih rendah, Anda masih dapat menggunakan kueri di atas jika tabel Anda tidak besar. Jika ada hasil untuk query di atas, maka itulah perbedaan dari 2 tabel berdasarkan perbandingan field 1,2,3,4. Untuk meningkatkan kinerja kueri, Anda juga dapat memfilternya berdasarkan tanggal (periksa bagian yang diberi komentar)
sumber
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])
Hasilnya nol, tetapi sumber berbeda!
Tapi:
( 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]) )
bekerja.
sumber
Saya memiliki masalah yang sama di SQL Server dan menulis skrip T-SQL ini untuk mengotomatiskan proses (sebenarnya ini adalah versi yang lebih sederhana, milik saya menulis semua perbedaan ke satu tabel untuk memudahkan pelaporan).
Perbarui 'MyTable' dan 'MyOtherTable' ke nama tabel yang ingin Anda bandingkan.
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.'+@ColName+' AS '+@Table1+@ColName+' ,t2.'+@ColName+' AS '+@Table2+@ColName+' FROM '+@Table1+' t1 LEFT JOIN '+@Table2+' t2 ON t1.Identifier = t2.Identifier WHERE t1.'+@ColName+' <> t2.'+@ColName) SET @Counter = @Counter - 1 END
sumber
Saya menulis ini untuk membandingkan hasil dari tampilan yang cukup buruk yang saya porting dari Oracle ke SQL Server. Ini membuat sepasang tabel temp, #DataVariances dan #SchemaVariances, dengan perbedaan (Anda dapat menebaknya) data dalam tabel dan skema tabel itu sendiri.
Ini membutuhkan kedua tabel memiliki kunci utama, tetapi Anda bisa meletakkannya ke tempdb dengan kolom identitas jika tabel sumber tidak memilikinya.
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.'
sumber
Sebagian besar tanggapan tampaknya mengabaikan isu yang diangkat oleh Kamil. (Di situlah tabel berisi baris yang identik, tetapi baris yang berbeda diulang di setiap tabel.) Sayangnya, saya tidak dapat menggunakan solusinya, karena saya berada di Oracle. Yang terbaik yang bisa saya dapatkan adalah:
SELECT * FROM ( SELECT column1, column2, ..., COUNT(*) AS the_count FROM tableA GROUP BY column1, column2, ... MINUS SELECT column1, column2, ..., COUNT(*) AS the_count FROM tableB GROUP BY column1, column2, ... ) UNION ALL ( SELECT column1, column2, ..., COUNT(*) AS the_count FROM tableB GROUP BY column1, column2, ... MINUS SELECT column1, column2, ..., COUNT(*) AS the_count FROM tableA GROUP BY column1, column2, ... )
sumber
Untuk membandingkan T1 (PK, A, B) dan T2 (PK, A, B).
Pertama, bandingkan kumpulan kunci utama untuk mencari nilai kunci yang hilang di kedua sisi:
SELECT T1.*, T2.* FROM T1 FULL OUTER JOIN T2 ON T1.PK=T2.PK WHERE T1.PK IS NULL OR T2.PK IS NULL;
Kemudian daftarkan semua ketidakcocokan nilai:
SELECT T1.PK, 'A' AS columnName, T1.A AS leftValue, T2.A AS rightValue FROM T1 JOIN T2 ON T1.PK=T2.PK WHERE COALESCE(T1.A,0) != COALESCE(T2.A,0) UNION ALL SELECT T1.PK, 'B' AS columnName, T1.B AS leftValue, T2.B AS rightValue FROM T1 JOIN T2 ON T1.PK=T2.PK WHERE COALESCE(T1.B,0) != COALESCE(T2.B,0)
A dan B harus berjenis sama. Anda dapat menggunakan INFORMATION SCHEMA untuk menghasilkan SELECT. Jangan lupa COALESCE untuk juga menyertakan hasil IS NULL. Anda juga bisa menggunakan FULL OUTER JOIN dan COALESCE (T1.PK, 0) = COALESCE (T2.PK, 0).
Misalnya untuk kolom berjenis varchar:
SELECT concat('SELECT T1.PK, ''', COLUMN_NAME, ''' AS columnName, T1.', COLUMN_NAME, ' AS leftValue, T2.', COLUMN_NAME, ' AS rightValue FROM T1 JOIN T2 ON T1.PK=T2.PK WHERE COALESCE(T1.',COLUMN_NAME, ',0)!=COALESCE(T2.', COLUMN_NAME, ',0)') FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='T1' AND DATA_TYPE IN ('nvarchar','varchar');
sumber
Kita dapat membandingkan data dari dua tabel tabel DB2 menggunakan query sederhana di bawah ini,
Langkah 1: - Pilih semua kolom yang perlu kita bandingkan dari tabel (T1) skema (S)
SELECT T1.col1,T1.col3,T1.col5 from S.T1
Langkah 2: - Gunakan kata kunci 'Minus' untuk membandingkan 2 tabel.
Langkah 3: - Pilih semua kolom yang perlu kita bandingkan dari tabel (T2) skema (S)
SELECT T2.col1,T2.col3,T2.col5 from S.T1
Hasil akhir:
SELECT T1.col1,T1.col3,T1.col5 from S.T1 MINUS SELECT T2.col1,T2.col3,T2.col5 from S.T1;
Jika kueri tidak mengembalikan baris maka datanya sama persis.
sumber
Di MySQL, di mana "minus" tidak didukung, dan dengan mempertimbangkan kinerja, ini adalah cara yang cepat
query: SELECT t1.id, t1.id FROM t1 inner join t2 using (id) where concat(t1.C, t1.D, ...)<>concat(t2.C, t2.D, ...)
sumber
Sebuah alternatif, kueri yang disempurnakan berdasarkan jawaban oleh dietbuddha & IanMc. Kueri menyertakan deskripsi untuk membantu menunjukkan di mana baris ada dan hilang. (NB: untuk 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 )
sumber
SELECT * FROM TABLE A WHERE NOT EXISTS (SELECT 'X' FROM TABLE B WHERE B.KEYFIELD1 = A.KEYFIELD1 AND B.KEYFIELD2 = A.KEYFIELD2 AND B.KEYFIELD3 = A.KEYFIELD3) ;
'X' adalah nilai apa pun.
Ganti tabel untuk melihat perbedaan yang berbeda.
Pastikan untuk menggabungkan bidang kunci di tabel Anda.
Atau cukup gunakan operator MINUS dengan 2 pernyataan pilih, namun MINUS hanya dapat bekerja di Oracle.
sumber