【问题标题】:sql query to return differences between two tablessql查询返回两个表之间的差异
【发布时间】:2011-01-05 21:00:24
【问题描述】:

我正在尝试比较两个表 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)

但是当我知道 td 中至少有 1 行不在 d 中时,我一直得到 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])))

这基本上是要告诉我我的测试数据中有什么在我的真实数据中不是。这对于我需要做的事情来说完全没问题。

【问题讨论】:

  • 下面的 EXCEPT 示例比这个快大约 100 倍。
  • 有人可以确认这是否有效吗?对我来说不起作用,如果在任何地方都没有使用“d”,也看不到“AS d”的意义,那里可能有错误吗?

标签: sql sql-server sql-server-2008 sql-server-2005


【解决方案1】:

存在与左连接和大数据完全连接相关的性能问题。

在我看来这是最好的解决方案:

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

【讨论】:

    【解决方案2】:

    您可以使用 except ,例如:

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

    【讨论】:

      【解决方案3】:

      将 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
      

      【讨论】:

        【解决方案4】:

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

        【讨论】:

        • 我收到错误All queries combined using a UNION, INTERSECT or EXCEPT operator must have an equal number of expressions in their target lists. 与此选择。我必须将'table1' as source, 部分也添加到除部分。 - 我为此编辑了答案。
        【解决方案5】:

        要获取两个表之间的所有差异,您可以像我一样使用这个 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
        ;
        

        【讨论】:

          【解决方案6】:

          这将起到作用,与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 列中您将有表引用。

          【讨论】:

            【解决方案7】:

            对于一个简单的冒烟测试,您试图确保两个表匹配而无需担心列名:

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

            您可以轻松编写存储过程来比较一批表。

            【讨论】:

              【解决方案8】:

              如果要获取不同的列值,可以使用实体-属性-值模型:

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

              【讨论】:

              【解决方案9】:

              我知道这可能不是一个受欢迎的答案,但我同意@Randy Minder 在需要更复杂的比较时使用第三方工具。

              这里的这个具体案例很简单,对于这种情况,不需要这样的工具,但是如果你引入更多的列、两台服务器上的数据库、更复杂的比较标准等,这很容易变得复杂。

              这些工具有很多,例如ApexSQL Data DiffQuest Toad,您可以随时在试用模式下使用它们来完成工作。

              【讨论】:

              • Diffkit 是一个与 FOSS 数据库无关的解决方案的示例,该解决方案适用于来自各种数据库或文件系统的任何表格数据源。
              • Microsoft 还有一个 SQL Server tablediff 命令行实用程序,称为 here
              【解决方案10】:
              (   SELECT * FROM table1
                  EXCEPT
                  SELECT * FROM table2)  
              UNION ALL
              (   SELECT * FROM table2
                  EXCEPT
                  SELECT * FROM table1) 
              

              【讨论】:

              • 太棒了!它对我有用,我从两个不同服务器上的两个不同数据库中提取两个表。
              • 我也收到一个错误,消息 205,级别 16,状态 1,第 5 行所有使用 UNION、INTERSECT 或 EXCEPT 运算符组合的查询必须在其目标列表中具有相同数量的表达式。
              • 如果您遇到错误,您需要确保以相同的顺序选择相同的字段(相同类型)。 SELECT * 适用于所有列的情况;如果没有,只需选择一些子集。
              • 很好的答案。有没有办法可以添加一个字段来告诉我返回的记录来自两个表中的哪一个?
              • 小心,因为此解决方案会丢弃重复项。
              【解决方案11】:

              试试这个:

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

              阅读起来更简单。

              【讨论】:

                【解决方案12】:

                如果您有表 AB,两者都有列 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 的列将为空。

                【讨论】:

                • 我无法正常工作,请参阅我最近的编辑。
                • 问题可能是您无法使用“=”将值与空值进行比较。 (或者至少在 SET ANSI_NULLS 为 ON 时。)您必须说:value IS NULL 或 value IS NOT NULL。
                • 我将此标记为我使用的答案,因为通过这种方式,我能够轻松地做一些我以后必须做的其他事情。
                • The objects "a.dbo.student" and "b.dbo.student" in the FROM clause have the same exposed names. Use correlation names to distinguish them. 如果表名相同并且您从两个不同的数据库中提取它们,则会出现错误。
                • @Thecrocodilehunter 您需要更改表的名称,例如 a.dbo.student asb.dbo.student bs 然后参考带有 asbs 的表
                猜你喜欢
                • 1970-01-01
                • 2015-07-12
                • 2013-06-30
                • 2015-01-16
                • 1970-01-01
                • 2015-03-19
                • 2011-12-21
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多