sql 쿼리: 두 테이블 간의 차이를 반환합니다.
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)
그러나 td에 d 단위가 아닌 행이 적어도1개 있는 것을 알고 있으면, 계속 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])))
기본적으로 테스트 데이터에는 없지만 실제 데이터에는 없는 정보가 표시됩니다.내가 해야 할 일에는 전혀 문제가 없어요
( SELECT * FROM table1
EXCEPT
SELECT * FROM table2)
UNION ALL
( SELECT * FROM table2
EXCEPT
SELECT * FROM table1)
이 A ★★★★★★★★★★★★★★★★★」B다 colum(콜럼 포함)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보다)BNULL이 NULL에 로 NULL이 됩니다.B in in A의 .A무효가 됩니다.
이것이 일반적인 답변이 아닐 수도 있다는 것을 알지만, 더 복잡한 비교가 필요할 때 서드파티 툴을 사용하는 것에 대해서는 @Randy Minder의 의견에 동의합니다.
여기서 설명하는 특정 케이스는 쉽고, 이 케이스에서는 이러한 툴이 필요하지 않지만, 2대의 서버에 더 많은 열, 데이터베이스, 더 복잡한 비교 기준 등을 도입하면 이 문제가 복잡해질 수 있습니다.
ApexSQL Data Diff 또는 Quest Toad와 같은 많은 툴이 있으며, 작업을 완료하기 위해 언제든지 평가 모드에서 사용할 수 있습니다.
두 테이블의 차이를 모두 파악하려면 나처럼 다음 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
;
행이 존재하는 테이블을 나타내는 @erikkallen 답변의 간단한 변형:
( SELECT 'table1' as source, * FROM table1
EXCEPT
SELECT * FROM table2)
UNION ALL
( SELECT 'table2' as source, * FROM table2
EXCEPT
SELECT * FROM table1)
에러가 발생했을 경우
UNION, CRESS 또는 EXECT 연산자를 사용하여 결합된 모든 쿼리는 대상 목록에 동일한 수의 식이 있어야 합니다.
추가에 도움이 될 수 있습니다.
( 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)
서로 다른 열 값을 가져오려면 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
)
Diffs의 캐딜락을 SP로 제시합니다.@erikkallen의 답변을 기반으로 한 기본 템플릿에 대해서는 내부를 참조하십시오.서포트
- 중복 행 감지(여기에 있는 대부분의 다른 답변은 해당되지 않음)
- 인수로 결과 정렬
- 특정 열로 제한
- 열 무시(예: Modified Utc)
- 교차 데이터베이스 테이블 이름
- 임시 테이블(다른 뷰의 회피책으로 사용)
사용방법:
exec Common.usp_DiffTableRows '#t1', '#t2';
exec Common.usp_DiffTableRows
@pTable0 = 'ydb.ysh.table1',
@pTable1 = 'xdb.xsh.table2',
@pOrderByCsvOpt = null, -- Order the results
@pOnlyCsvOpt = null, -- Only compare these columns
@pIgnoreCsvOpt = null; -- Ignore these columns (ignored if @pOnlyCsvOpt is specified)
코드:
alter proc [Common].[usp_DiffTableRows]
@pTable0 varchar(300),
@pTable1 varchar(300),
@pOrderByCsvOpt nvarchar(1000) = null, -- Order the Results
@pOnlyCsvOpt nvarchar(4000) = null, -- Only compare these columns
@pIgnoreCsvOpt nvarchar(4000) = null, -- Ignore these columns (ignored if @pOnlyCsvOpt is specified)
@pDebug bit = 0
as
/*---------------------------------------------------------------------------------------------------------------------
Purpose: Compare rows between two tables.
Usage: exec Common.usp_DiffTableRows '#a', '#b';
Modified By Description
---------- ---------- -------------------------------------------------------------------------------------------
2015.10.06 crokusek Initial Version
2019.03.13 crokusek Added @pOrderByCsvOpt
2019.06.26 crokusek Support for @pIgnoreCsvOpt, @pOnlyCsvOpt.
2019.09.04 crokusek Minor debugging improvement
2020.03.12 crokusek Detect duplicate rows in either source table
---------------------------------------------------------------------------------------------------------------------*/
begin try
if (substring(@pTable0, 1, 1) = '#')
set @pTable0 = 'tempdb..' + @pTable0; -- object_id test below needs full names for temp tables
if (substring(@pTable1, 1, 1) = '#')
set @pTable1 = 'tempdb..' + @pTable1; -- object_id test below needs full names for temp tables
if (object_id(@pTable0) is null)
raiserror('Table name is not recognized: ''%s''', 16, 1, @pTable0);
if (object_id(@pTable1) is null)
raiserror('Table name is not recognized: ''%s''', 16, 1, @pTable1);
create table #ColumnGathering
(
Name nvarchar(300) not null,
Sequence int not null,
TableArg tinyint not null
);
declare
@usp varchar(100) = object_name(@@procid),
@sql nvarchar(4000),
@sqlTemplate nvarchar(4000) =
'
use $database$;
insert into #ColumnGathering
select Name, column_id as Sequence, $TableArg$ as TableArg
from sys.columns c
where object_id = object_id(''$table$'', ''U'')
';
set @sql = replace(replace(replace(@sqlTemplate,
'$TableArg$', 0),
'$database$', (select DatabaseName from Common.ufn_SplitDbIdentifier(@pTable0))),
'$table$', @pTable0);
if (@pDebug = 1)
print 'Sql #CG 0: ' + @sql;
exec sp_executesql @sql;
set @sql = replace(replace(replace(@sqlTemplate,
'$TableArg$', 1),
'$database$', (select DatabaseName from Common.ufn_SplitDbIdentifier(@pTable1))),
'$table$', @pTable1);
if (@pDebug = 1)
print 'Sql #CG 1: ' + @sql;
exec sp_executesql @sql;
if (@pDebug = 1)
select * from #ColumnGathering;
select Name,
min(Sequence) as Sequence,
convert(bit, iif(min(TableArg) = 0, 1, 0)) as InTable0,
convert(bit, iif(max(TableArg) = 1, 1, 0)) as InTable1
into #Columns
from #ColumnGathering
group by Name
having ( @pOnlyCsvOpt is not null
and Name in (select Value from Common.ufn_UsvToNVarcharKeyTable(@pOnlyCsvOpt, default)))
or
( @pOnlyCsvOpt is null
and @pIgnoreCsvOpt is not null
and Name not in (select Value from Common.ufn_UsvToNVarcharKeyTable(@pIgnoreCsvOpt, default)))
or
( @pOnlyCsvOpt is null
and @pIgnoreCsvOpt is null)
if (exists (select 1 from #Columns where InTable0 = 0 or InTable1 = 0))
begin
select 1; -- without this the debugging info doesn't stream sometimes
select * from #Columns order by Sequence;
waitfor delay '00:00:02'; -- give results chance to stream before raising exception
raiserror('Columns are not equal between tables, consider using args @pIgnoreCsvOpt, @pOnlyCsvOpt. See Result Sets for details.', 16, 1);
end
if (@pDebug = 1)
select * from #Columns order by Sequence;
declare
@columns nvarchar(4000) = --iif(@pOnlyCsvOpt is null and @pIgnoreCsvOpt is null,
-- '*',
(
select substring((select ',' + ac.name
from #Columns ac
order by Sequence
for xml path('')),2,200000) as csv
);
if (@pDebug = 1)
begin
print 'Columns: ' + @columns;
waitfor delay '00:00:02'; -- give results chance to stream before possibly raising exception
end
-- Based on https://stackoverflow.com/a/2077929/538763
-- - Added sensing for duplicate rows
-- - Added reporting of source table location
--
set @sqlTemplate = '
with
a as (select ~, Row_Number() over (partition by ~ order by (select null)) -1 as Duplicates from $a$),
b as (select ~, Row_Number() over (partition by ~ order by (select null)) -1 as Duplicates from $b$)
select 0 as SourceTable, ~
from
(
select * from a
except
select * from b
) anb
union all
select 1 as SourceTable, ~
from
(
select * from b
except
select * from a
) bna
order by $orderBy$
';
set @sql = replace(replace(replace(replace(@sqlTemplate,
'$a$', @pTable0),
'$b$', @pTable1),
'~', @columns),
'$orderBy$', coalesce(@pOrderByCsvOpt, @columns + ', SourceTable')
);
if (@pDebug = 1)
print 'Sql: ' + @sql;
exec sp_executesql @sql;
end try
begin catch
declare
@CatchingUsp varchar(100) = object_name(@@procid);
if (xact_state() = -1)
rollback;
-- Disabled for S.O. post
--exec Common.usp_Log
--@pMethod = @CatchingUsp;
--exec Common.usp_RethrowError
--@pCatchingMethod = @CatchingUsp;
throw;
end catch
go
create function Common.Trim
(
@pOriginalString nvarchar(max),
@pCharsToTrim nvarchar(50) = null -- specify null or 'default' for whitespae
)
returns table
with schemabinding
as
/*--------------------------------------------------------------------------------------------------
Purpose: Trim the specified characters from a string.
Modified By Description
---------- -------------- --------------------------------------------------------------------
2012.09.25 S.Rutszy/crok Modified from https://dba.stackexchange.com/a/133044/9415
--------------------------------------------------------------------------------------------------*/
return
with cte AS
(
select patindex(N'%[^' + EffCharsToTrim + N']%', @pOriginalString) AS [FirstChar],
patindex(N'%[^' + EffCharsToTrim + N']%', reverse(@pOriginalString)) AS [LastChar],
len(@pOriginalString + N'~') - 1 AS [ActualLength]
from
(
select EffCharsToTrim = coalesce(@pCharsToTrim, nchar(0x09) + nchar(0x20) + nchar(0x0d) + nchar(0x0a))
) c
)
select substring(@pOriginalString, [FirstChar],
((cte.[ActualLength] - [LastChar]) - [FirstChar] + 2)
) AS [TrimmedString]
--
--cte.[ActualLength],
--[FirstChar],
--((cte.[ActualLength] - [LastChar]) + 1) AS [LastChar]
from cte;
go
create function [Common].[ufn_UsvToNVarcharKeyTable] (
@pCsvList nvarchar(MAX),
@pSeparator nvarchar(1) = ',' -- can pass keyword 'default' when calling using ()'s
)
--
-- SQL Server 2012 distinguishes nvarchar keys up to maximum of 450 in length (900 bytes)
--
returns @tbl table (Value nvarchar(450) not null primary key(Value)) as
/*-------------------------------------------------------------------------------------------------
Purpose: Converts a comma separated list of strings into a sql NVarchar table. From
http://www.programmingado.net/a-398/SQL-Server-parsing-CSV-into-table.aspx
This may be called from RunSelectQuery:
GRANT SELECT ON Common.ufn_UsvToNVarcharTable TO MachCloudDynamicSql;
Modified By Description
---------- -------------- -------------------------------------------------------------------
2011.07.13 internet Initial version
2011.11.22 crokusek Support nvarchar strings and a custom separator.
2017.12.06 crokusek Trim leading and trailing whitespace from each element.
2019.01.26 crokusek Remove newlines
-------------------------------------------------------------------------------------------------*/
begin
declare
@pos int,
@textpos int,
@chunklen smallint,
@str nvarchar(4000),
@tmpstr nvarchar(4000),
@leftover nvarchar(4000),
@csvList nvarchar(max) = iif(@pSeparator not in (char(13), char(10), char(13) + char(10)),
replace(replace(@pCsvList, char(13), ''), char(10), ''),
@pCsvList); -- remove newlines
set @textpos = 1
set @leftover = ''
while @textpos <= len(@csvList)
begin
set @chunklen = 4000 - len(@leftover)
set @tmpstr = ltrim(@leftover + substring(@csvList, @textpos, @chunklen))
set @textpos = @textpos + @chunklen
set @pos = charindex(@pSeparator, @tmpstr)
while @pos > 0
begin
set @str = substring(@tmpstr, 1, @pos - 1)
set @str = (select TrimmedString from Common.Trim(@str, default));
insert @tbl (value) values(@str);
set @tmpstr = ltrim(substring(@tmpstr, @pos + 1, len(@tmpstr)))
set @pos = charindex(@pSeparator, @tmpstr)
end
set @leftover = @tmpstr
end
-- Handle @leftover
set @str = (select TrimmedString from Common.Trim(@leftover, default));
if @str <> ''
insert @tbl (value) values(@str);
return
end
GO
create function Common.ufn_SplitDbIdentifier(@pIdentifier nvarchar(300))
returns @table table
(
InstanceName nvarchar(300) not null,
DatabaseName nvarchar(300) not null,
SchemaName nvarchar(300),
BaseName nvarchar(300) not null,
FullTempDbBaseName nvarchar(300), -- non-null for tempdb (e.g. #Abc____...)
InstanceWasSpecified bit not null,
DatabaseWasSpecified bit not null,
SchemaWasSpecified bit not null,
IsCurrentInstance bit not null,
IsCurrentDatabase bit not null,
IsTempDb bit not null,
OrgIdentifier nvarchar(300) not null
) as
/*-----------------------------------------------------------------------------------------------------------
Purpose: Split a Sql Server Identifier into its parts, providing appropriate default values and
handling temp table (tempdb) references.
Example: select * from Common.ufn_SplitDbIdentifier('t')
union all
select * from Common.ufn_SplitDbIdentifier('s.t')
union all
select * from Common.ufn_SplitDbIdentifier('d.s.t')
union all
select * from Common.ufn_SplitDbIdentifier('i.d.s.t')
union all
select * from Common.ufn_SplitDbIdentifier('#d')
union all
select * from Common.ufn_SplitDbIdentifier('tempdb..#d');
-- Empty
select * from Common.ufn_SplitDbIdentifier('illegal name');
Modified By Description
---------- -------------- -----------------------------------------------------------------------------
2013.09.27 crokusek Initial version.
-----------------------------------------------------------------------------------------------------------*/
begin
declare
@name nvarchar(300) = ltrim(rtrim(@pIdentifier));
-- Return an empty table as a "throw"
--
--Removed for SO post
--if (Common.ufn_IsSpacelessLiteralIdentifier(@name) = 0)
-- return;
-- Find dots starting from the right by reversing first.
declare
@revName nvarchar(300) = reverse(@name);
declare
@firstDot int = charindex('.', @revName);
declare
@secondDot int = iif(@firstDot = 0, 0, charindex('.', @revName, @firstDot + 1));
declare
@thirdDot int = iif(@secondDot = 0, 0, charindex('.', @revName, @secondDot + 1));
declare
@fourthDot int = iif(@thirdDot = 0, 0, charindex('.', @revName, @thirdDot + 1));
--select @firstDot, @secondDot, @thirdDot, @fourthDot, len(@name);
-- Undo the reverse() (first dot is first from the right).
--
set @firstDot = iif(@firstDot = 0, 0, len(@name) - @firstDot + 1);
set @secondDot = iif(@secondDot = 0, 0, len(@name) - @secondDot + 1);
set @thirdDot = iif(@thirdDot = 0, 0, len(@name) - @thirdDot + 1);
set @fourthDot = iif(@fourthDot = 0, 0, len(@name) - @fourthDot + 1);
--select @firstDot, @secondDot, @thirdDot, @fourthDot, len(@name);
declare
@baseName nvarchar(300) = substring(@name, @firstDot + 1, len(@name) - @firstdot);
declare
@schemaName nvarchar(300) = iif(@firstDot - @secondDot - 1 <= 0,
null,
substring(@name, @secondDot + 1, @firstDot - @secondDot - 1));
declare
@dbName nvarchar(300) = iif(@secondDot - @thirdDot - 1 <= 0,
null,
substring(@name, @thirdDot + 1, @secondDot - @thirdDot - 1));
declare
@instName nvarchar(300) = iif(@thirdDot - @fourthDot - 1 <= 0,
null,
substring(@name, @fourthDot + 1, @thirdDot - @fourthDot - 1));
with input as (
select
coalesce(@instName, '[' + @@servername + ']') as InstanceName,
coalesce(@dbName, iif(left(@baseName, 1) = '#', 'tempdb', db_name())) as DatabaseName,
coalesce(@schemaName, iif(left(@baseName, 1) = '#', 'dbo', schema_name())) as SchemaName,
@baseName as BaseName,
iif(left(@baseName, 1) = '#',
(
select [name] from tempdb.sys.objects
where object_id = object_id('tempdb..' + @baseName)
),
null) as FullTempDbBaseName,
iif(@instName is null, 0, 1) InstanceWasSpecified,
iif(@dbName is null, 0, 1) DatabaseWasSpecified,
iif(@schemaName is null, 0, 1) SchemaWasSpecified
)
insert into @table
select i.InstanceName, i.DatabaseName, i.SchemaName, i.BaseName, i.FullTempDbBaseName,
i.InstanceWasSpecified, i.DatabaseWasSpecified, i.SchemaWasSpecified,
iif(i.InstanceName = '[' + @@servername + ']', 1, 0) as IsCurrentInstance,
iif(i.DatabaseName = db_name(), 1, 0) as IsCurrentDatabase,
iif(left(@baseName, 1) = '#', 1, 0) as IsTempDb,
@name as OrgIdentifier
from input i;
return;
end
GO
예를 들어 다음과 같은 경우를 제외하고 를 사용할 수 있습니다.
-- 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
다음을 시도해 보십시오.
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])
훨씬 읽기 쉬워요.
그러면 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 열에는 테이블 참조가 표시됩니다.
두 개의 테이블이 일치하는지 확인하려는 간단한 스모크 테스트의 경우 열 이름을 우려하여 다음 작업을 수행합니다.
--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
표의 배치를 비교하는 저장 절차를 쉽게 작성할 수 있습니다.
왼쪽 조인 및 대용량 데이터와의 완전 조인 관련 성능 문제가 있습니다.
제 생각에는 이것이 최선의 해결책입니다.
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
EXCEPT ★★★★★★★★★★★★★★★★★」NOT EXISTS데이터 집합 간의 차이를 빠르게 찾는 좋은 방법이지만, 어떤 열이 다른지, 어떻게 다른지 알고 싶을 때가 많습니다.
때 이 되는 은 '이렇게 하다'를 사용하는 입니다.UNPIVOT열을 행별로 비교할 수 있는 키 값 쌍으로 변환합니다.
다만, 유용하게 사용하기 위해서는, 비교하고 싶은 레코드와 일치하는 방법이 필요합니다.예를 들어, 사회보장 번호나 「개인 ID」와 같은 것입니다.
CREATE TABLE [RealData]
(
[PersonId] INT,
[FirstName] NVARCHAR(100),
[LastName] NVARCHAR(100),
[ProductName] NVARCHAR(100)
)
CREATE TABLE [TempTestData]
(
[PersonId] INT,
[FirstName] NVARCHAR(100),
[LastName] NVARCHAR(100),
[ProductName] NVARCHAR(100)
)
INSERT INTO [RealData] ([PersonId], [FirstName], [LastName], [ProductName])
VALUES
(1, 'Al', 'Bundy', 'Ladies Size 12'),
(2, 'Peggy', 'Bundy', 'TV Guide')
INSERT INTO [TempTestData] ([PersonId], [FirstName], [LastName], [ProductName])
VALUES
(1, 'Al', 'Bundy', 'Ladies Size 13'),
(2, 'Peggy', 'Bundy', 'TV Guide')
★★★★★★★★★★★★★★★★.UNPIVOTCTE를 사용하다
;WITH RealDataCte AS (
SELECT
'Real Data' AS [DataSource],
unpivotedRealData.*
FROM
(SELECT
CAST([PersonId] AS NVARCHAR(100)) AS [PersonId],
[FirstName],
[LastName],
[ProductName]
FROM [RealData]) AS realData
UNPIVOT
(ColumnValue FOR ColumnName IN ([FirstName], [LastName], [ProductName])) AS unpivotedRealData
),
TempTestDataCte AS (
SELECT
'Temp Test Data' AS [DataSource],
unpivotedDempTestData.*
FROM
(SELECT
CAST([PersonId] AS NVARCHAR(100)) AS [PersonId],
[FirstName],
[LastName],
[ProductName]
FROM [TempTestData]) AS tempTestData
UNPIVOT
(ColumnValue FOR ColumnName IN ([FirstName], [LastName], [ProductName])) AS unpivotedDempTestData
)
SELECT
RealDataCte.[DataSource],
RealDataCte.[ColumnName],
RealDataCte.[ColumnValue],
TempTestDataCte.[DataSource],
TempTestDataCte.[ColumnName],
TempTestDataCte.[ColumnValue],
CASE WHEN RealDataCte.[ColumnValue] <> TempTestDataCte.[ColumnValue] THEN 'YES' ELSE 'NO' END AS ColumnsDiffer
FROM RealDataCte
INNER JOIN
TempTestDataCte
ON RealDataCte.[ColumnName] = TempTestDataCte.[ColumnName]
AND RealDataCte.[PersonId] = TempTestDataCte.[PersonId]
WHERE
RealDataCte.[ColumnValue] <> TempTestDataCte.[ColumnValue]
그 결과, 2개의 제품이 다릅니다.
여러 행에서 비교할 열이 여러 개 있는 경우 유용합니다.
설정에는 수 , 컬럼 해야 합니다.다소 수 있습니다().CAST(PersonId 경경 )) )
데이터 세트가 매우 큰 경우 CTE 대신 임시 테이블을 사용할 수도 있습니다.
잘 될 거야서로 다른 두 테이블의 행 수 차이를 찾기 위한 선택 쿼리
select (t1 - t2) as count_diff from (select (select count(*) from tbl1) t1, (select count(*) from tbl2) t2)
평판이 좋지 않아서 댓글을 달 수가 없어요.그건 말도 안 돼.
@Juan Vellez에게 가장 많은 표를 얻은 답변으로 답하는 것이 해결책을 제시합니다.
( SELECT * FROM table1
EXCEPT
SELECT * FROM table2)
UNION ALL
( SELECT * FROM table2
EXCEPT
SELECT * FROM table1)
후안이 "어느 테이블이 몇 줄인지 어떻게 알아?"라고 물었어요.
쿼리의 이 부분에서는 표 2에 없는 표 1의 모든 행을 선택합니다.
( SELECT * FROM @table1
EXCEPT
SELECT * FROM @table2)
쿼리의 이 부분에서는 표 1에 없는 표 2의 모든 행을 선택합니다.
( SELECT * FROM @table2
EXCEPT
SELECT * FROM @table1)
UNION ALL은 이들을 조합하기만 하면 됩니다.그러면 한 테이블에서 다른 테이블에서 누락된 행이 없는지 확인할 수 있습니다.개별적인 차이를 보고 싶다면
INSERT INTO @table1NotTable2
SELECT * FROM @table1
EXCEPT
SELECT * FROM @table2
INSERT INTO @table2NotTable1
SELECT * FROM @table2
EXCEPT
SELECT * FROM @table1
그리고 그의 답변과 같은 최종 결과를 얻으려면
SELECT * FROM @table1NotTable2
UNION ALL
SELECT * FROM @table2NotTable1
복사/붙여넣기 템플릿으로 원하는 사용자:
DECLARE @table1 TABLE (
)
DECLARE @table1NotTable2 TABLE (
)
DECLARE @table2 TABLE (
)
DECLARE @table2NotTable1 TABLE (
)
INSERT INTO @table1 (
)
INSERT INTO @table2 (
)
INSERT INTO @table1NotTable2
SELECT * FROM @table1
EXCEPT
SELECT * FROM @table2
INSERT INTO @table2NotTable1
SELECT * FROM @table2
EXCEPT
SELECT * FROM @table1
SELECT * FROM @table1NotTable2
SELECT * FROM @table2NotTable1
SELECT * FROM @table1NotTable2 UNION ALL SELECT * FROM @table2NotTable1
언급URL : https://stackoverflow.com/questions/2077807/sql-query-to-return-differences-between-two-tables
'source' 카테고리의 다른 글
| 테이블의 열에서 ID 제거 (0) | 2023.04.07 |
|---|---|
| 단일 사용자 모드 종료 (0) | 2023.04.07 |
| 데이터를 다른 테이블로 복사 (0) | 2023.04.07 |
| 인덱스를 작성할 때 INCLUDE 절을 사용하는 이유는 무엇입니까? (0) | 2023.04.07 |
| 레코드가 존재하는지 여부를 확인하는 가장 빠른 방법 (0) | 2023.04.07 |
