sql-запрос для возврата различий между двумя таблицами

Я пытаюсь сравнить две таблицы SQL Server, чтобы проверить некоторые данные. Я хочу вернуть все строки из обеих таблиц, где данные находятся либо в одной, либо в другой. По сути, хочу показать все неточности. При этом мне нужно проверить три части данных: FirstName, LastName и Product.

Я новичок в 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)

Но я продолжаю получать 0 результатов, когда знаю, что в td есть хотя бы 1 строка, которой нет в d.

РЕДАКТИРОВАТЬ:

Хорошо, думаю, я разобрался. По крайней мере, за несколько минут тестирования он работает достаточно хорошо.

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

Это в основном скажет мне, что в моих тестовых данных нет в моих реальных данных. Что совершенно нормально для того, что мне нужно делать.


person Casey    schedule 16.01.2010    source источник
comment
Пример EXCEPT ниже примерно в 100 раз быстрее, чем этот.   -  person Eric Hanson    schedule 21.01.2014
comment
может кто-нибудь подтвердить, работает ли это? не работает на моем конце, также не вижу смысла AS d, если d нигде не используется, может быть где-то там ошибка?   -  person Robert Sinclair    schedule 17.03.2017


Ответы (12)


ЕСЛИ у вас есть таблицы A и B, обе с столбцом 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, тогда столбцы, которые происходят из B, будут NULL, и аналогично для тех, которые присутствуют в B, а не в A , столбцы из A будут пустыми.

person treaschf    schedule 16.01.2010
comment
У меня проблемы с работой, см. Мои недавние изменения вверху. - person Casey; 16.01.2010
comment
Проблема может заключаться в том, что вы не можете сравнить значение с нулем, используя '='. (Или, по крайней мере, когда SET ANSI_NULLS установлен в ON.) Вы должны сказать: значение IS NULL или значение NOT NULL. - person treaschf; 16.01.2010
comment
Я отмечаю это как ответ, который я использовал, потому что, поступая таким образом, я мог легко сделать еще несколько вещей, которые мне пришлось сделать позже. - person Casey; 31.01.2010
comment
The objects "a.dbo.student" and "b.dbo.student" in the FROM clause have the same exposed names. Use correlation names to distinguish them. Я получаю сообщение об ошибке, если имена таблиц совпадают и вы извлекаете их из двух разных баз данных. - person Hammad Khan; 20.07.2011
comment
@Thecrocodilehunter, вам нужно изменить имя таблиц, например a.dbo.student as и b.dbo.student bs, затем обратиться к таблицам с as и bs - person AaA; 08.03.2012
comment
По крайней мере, для меня это волшебство. - person MindRoasterMir; 19.07.2021

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

Этот конкретный случай здесь прост, и для этого случая такие инструменты не нужны, но это может легко усложниться, если вы введете больше столбцов, базы данных на двух серверах, более сложные критерии сравнения и т. Д.

Существует множество таких инструментов, как ApexSQL Data Diff или Quest Toad, и вы всегда можете использовать их в пробном режиме, чтобы выполнить свою работу.

person Maisie John    schedule 14.05.2013
comment
Примером решения FOSS, не зависящего от базы данных, которое работает с любыми табличными источниками данных из различных баз данных или файловых систем, является Diffkit . - person wwmbes; 03.02.2017

Чтобы получить все различия между двумя таблицами, вы можете использовать, как я, этот 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
;
person bilelovitch    schedule 07.12.2015

Простой вариант ответа @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) 
person studgeek    schedule 14.12.2016
comment
Я получаю сообщение об ошибке All queries combined using a UNION, INTERSECT or EXCEPT operator must have an equal number of expressions in their target lists. с этим выбором. Мне пришлось добавить часть 'table1' as source, также в часть Except. - Я отредактировал ответ по этому поводу. - person knut; 04.07.2018

Если вы хотите узнать, какие значения столбцов отличаются, вы можете использовать модель 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

person Roman Pekar    schedule 26.07.2013
comment
Спасибо, я сделал этот код немного динамичным. Теперь он позволяет передавать две таблицы, которые вы хотите сравнить ... thitos.blogspot.com/2014/03/compare-data-from-two-tables.html - person Thato; 11.03.2014

Попробуй это :

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

Гораздо проще читать.

person Kango_V    schedule 16.01.2010

Это сработает, аналогично решению 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 будет ссылка на таблицу.

person Adrian-Bogdan Ionescu    schedule 02.11.2014

Представляем Cadillac of Diffs как SP. См. Основной шаблон, основанный на ответе @erikkallen. Он поддерживает

  • Обнаружение повторяющейся строки (большинство других ответов здесь нет)
  • Сортировать результаты по аргументу
  • Ограничить определенными столбцами
  • Игнорировать столбцы (например, ModifiedUtc)
  • Имена таблиц кросс-базы данных
  • Временные таблицы (используйте как обходной путь для просмотра различий)

Использование:

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
person crokusek    schedule 13.03.2020

Вы можете использовать, например, что-то вроде этого:

-- 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
person GiovaniSalazar    schedule 15.08.2019

Для простого дымового теста, когда вы пытаетесь убедиться, что две таблицы совпадают, не беспокоясь об именах столбцов:

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

Вы можете легко написать процедуру хранения для сравнения пакета таблиц.

person thomas398    schedule 22.11.2013

Существует проблема производительности, связанная с левым соединением, а также с полным соединением с большими данными.

На мой взгляд, это лучшее решение:

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
person Tiago Moutinho    schedule 10.09.2014

person    schedule
comment
Я получаю ошибку при использовании этого. Я беру две таблицы из двух разных баз данных - person Hammad Khan; 20.07.2011
comment
Превосходно! У меня это сработало, и я извлекаю две таблицы из двух разных баз данных на двух разных серверах. - person dotnetN00b; 10.05.2012
comment
Я также получаю сообщение об ошибке: Msg 205, Level 16, State 1, Line 5. Все запросы, объединенные с помощью оператора UNION, INTERSECT или EXCEPT, должны иметь равное количество выражений в своих целевых списках. - person cdub; 05.02.2013
comment
Если вы получаете сообщение об ошибке, убедитесь, что вы выбрали одни и те же поля (одинаковые типы) в том же порядке. SELECT * работает, если это так для всех столбцов; если нет, просто выберите какое-нибудь подмножество. - person ashes999; 11.03.2013
comment
Любой, у кого есть опыт работы с большими наборами данных, мог бы сказать мне, будет ли это решение работать для таблиц с 500 000+ строками, а как насчет 50 миллионов строк? - person Michiel Cornille; 05.07.2013
comment
Да, и это МИНУС в Oracle, и он намного производительнее, чем варианты левого внешнего соединения. Мне было бы интересно узнать, почему. - person Patrick Fromberg; 14.04.2014
comment
Мы используем другой сервер с копиями наших живых таблиц в качестве тестовой среды. Для параллельного тестирования с таким запросом на 2 разных серверах это может предоставить дополнительную помощь: stackoverflow.com/a/22342227/1681303 - person Milne; 29.09.2016
comment
Отличный ответ. Есть ли способ добавить поле, которое сообщит мне, из какой из двух таблиц были возвращены записи? - person Juan Velez; 18.10.2016
comment
@ pokerplayer23 Я добавил ответ, который показывает здесь исходную таблицу - stackoverflow.com/a/41150408/255961 - person studgeek; 14.12.2016
comment
Будьте осторожны, так как это решение отбрасывает дубликаты. - person Jin Kim; 03.08.2017
comment
Если этот запрос не возвращает результатов и это из-за дубликатов, как кто-то сказал ранее, используйте группу по всем столбцам, имеющим count (*) ›1, чтобы найти добавленные. - person user890332; 25.08.2019
comment
Не будет работать в Big Query: Message: EXCEPT must be followed by ALL, DISTINCT, or "(" - person motobói; 27.10.2020
comment
@ motobói С BigQuery я столкнулся с той же проблемой. Я обнаружил, что BigQuery поддерживает только EXCEPT DISTINCT. К сожалению, EXCEPT ALL не поддерживается BigQuery. - person nclskfm; 31.10.2020
comment
УХ ТЫ! Это сработало - спасибо! - person Vnuuk; 03.02.2021