AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 12580
Accepted
ErikE
ErikE
Asked: 2012-02-10 11:51:19 +0800 CST2012-02-10 11:51:19 +0800 CST 2012-02-10 11:51:19 +0800 CST

轻松显示两个表或查询之间不同的行

  • 772

想象一下,您有两个不同的表/查询,它们应该具有/返回相同的数据。你想验证这一点。什么是显示每个表中任何不匹配行的简单方法,就像下面的示例一样,比较每一列?假设表中有 30 列,其中许多列可以为 NULL。

当没有 PK 或每个 PK 可能有重复项时,仅加入 PK 列是不够的,并且必须使用 30 个正确处理 NULL 的连接条件以及令人讨厌的 WHERE 条件进行 FULL JOIN 将是一场灾难排除匹配的行。

通常,当我针对未清理或未完全理解的数据编写新查询时,问题最严重,并且 PK 在逻辑上可用的可能性极低。我设计了两种不同的方法来解决问题,然后比较它们的结果,这些差异突出了我不知道的数据中的特殊情况。

结果需要如下所示:

Which   Col1   Col2   Col3   ... Col30
------  ------ ------ ------     ------
TableA  Cat    27     86               -- mismatch
TableB  Cat    27     105              -- mismatch
TableB  Cat    27     87               -- mismatch 2
TableA  Cat    128    92               -- no corresponding row
TableB  Lizard 83     NULL             -- no corresponding row

如果[Col1, Col2]确实是一个复合键,并且我们在最终结果中按它们排序,那么我们可以很容易地看到 A 和 B 有一行不同但应该是相同的,并且每一行都有另一行不存在。

在上面的示例中,不希望看到第一行两次。

这是用于设置示例表和数据的 DDL 和 DML:

CREATE TABLE dbo.TableA (
   Col1 varchar(10),
   Col2 int,
   Col3 int,
   Col4 varchar(10),
   Col5 varchar(10),
   Col6 varchar(10),
   Col7 varchar(10),
   Col8 varchar(10),
   Col9 varchar(10),
   Col10 varchar(10),
   Col11 varchar(10),
   Col12 varchar(10),
   Col13 varchar(10),
   Col14 varchar(10),
   Col15 varchar(10),
   Col16 varchar(10),
   Col17 varchar(10),
   Col18 varchar(10),
   Col19 varchar(10),
   Col20 varchar(10),
   Col21 varchar(10),
   Col22 varchar(10),
   Col23 varchar(10),
   Col24 varchar(10),
   Col25 varchar(10),
   Col26 varchar(10),
   Col27 varchar(10),
   Col28 varchar(10),
   Col29 varchar(10),
   Col30 varchar(10)
);

CREATE TABLE dbo.TableB (
   Col1 varchar(10),
   Col2 int,
   Col3 int,
   Col4 varchar(10),
   Col5 varchar(10),
   Col6 varchar(10),
   Col7 varchar(10),
   Col8 varchar(10),
   Col9 varchar(10),
   Col10 varchar(10),
   Col11 varchar(10),
   Col12 varchar(10),
   Col13 varchar(10),
   Col14 varchar(10),
   Col15 varchar(10),
   Col16 varchar(10),
   Col17 varchar(10),
   Col18 varchar(10),
   Col19 varchar(10),
   Col20 varchar(10),
   Col21 varchar(10),
   Col22 varchar(10),
   Col23 varchar(10),
   Col24 varchar(10),
   Col25 varchar(10),
   Col26 varchar(10),
   Col27 varchar(10),
   Col28 varchar(10),
   Col29 varchar(10),
   Col30 varchar(10)
);

INSERT dbo.TableA (Col1, Col2, Col3, Col4, Col5, Col6, Col7, Col8, Col9, Col10, Col11, Col12, Col13, Col14, Col15, Col16, Col17, Col18, Col19, Col20, Col21, Col22, Col23, Col24, Col25, Col26, Col27, Col28, Col29, Col30)
VALUES
   ('Cat', 27, 86, 'a', 'b', 'c', 'd', 'e', 'f', 'g',' h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0'),
   ('Cat', 128, 92, 'a', 'b', 'c', 'd', 'e', 'f', 'g',' h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0'),
   ('Porcupine', NULL, 42, 'a', 'b', 'c', 'd', 'e', 'f', 'g',' h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0'),
   ('Tapir', NULL, NULL, 'a', 'b', 'c', 'd', 'e', 'f', 'g',' h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0')
;

INSERT dbo.TableB (Col1, Col2, Col3, Col4, Col5, Col6, Col7, Col8, Col9, Col10, Col11, Col12, Col13, Col14, Col15, Col16, Col17, Col18, Col19, Col20, Col21, Col22, Col23, Col24, Col25, Col26, Col27, Col28, Col29, Col30)
VALUES
   ('Cat', 27, 105, 'a', 'b', 'c', 'd', 'e', 'f', 'g',' h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0'),
   ('Cat', 27, 87, 'a', 'b', 'c', 'd', 'e', 'f', 'g',' h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0'),
   ('Lizard', 83, NULL, 'a', 'b', 'c', 'd', 'e', 'f', 'g',' h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0'),
   ('Porcupine', NULL, 42, 'a', 'b', 'c', 'd', 'e', 'f', 'g',' h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0'),
   ('Tapir', NULL, NULL, 'a', 'b', 'c', 'd', 'e', 'f', 'g',' h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0');
sql-server sql-server-2008
  • 4 4 个回答
  • 112502 Views

4 个回答

  • Voted
  1. hqrsie
    2012-02-10T11:58:00+08:002012-02-10T11:58:00+08:00

    这可以使用 EXCEPT 和/或 INTERSECT 来处理。 http://msdn.microsoft.com/en-us/library/ms188055.aspx

    首先查找表 1 中所有不在表 2 中的记录,然后查找表 2 中所有不在表 1 中的记录。

    SELECT * FROM table1
    EXCEPT
    SELECT * FROM table2
    
    UNION
    
    SELECT * FROM table2
    EXCEPT
    SELECT * FROM table1
    

    毫无疑问,有一种更有效的方法可以做到这一点,但这是我脑海中第一个“快速而肮脏”的解决方案。另外,我不建议使用 * 通配符,但为了简洁起见,它适合这里。

    或者,您可以使用 INTERSECT 运算符并从中排除所有结果。

    • 23
  2. Best Answer
    Martin Smith
    2012-02-11T04:19:52+08:002012-02-11T04:19:52+08:00

    这里不需要 30 个加入条件FULL OUTER JOIN。

    您可以只在 PK 上进行完全外连接,保留至少有一个差异的行,WHERE EXISTS (SELECT A.* EXCEPT SELECT B.*)并用于CROSS APPLY (SELECT A.* UNION ALL SELECT B.*)将 ed 行的两侧反旋转JOIN成单独的行。

    WITH TableA(Col1, Col2, Col3) 
         AS (SELECT 'Dog',1,1     UNION ALL 
             SELECT 'Cat',27,86   UNION ALL 
             SELECT 'Cat',128,92), 
         TableB(Col1, Col2, Col3) 
         AS (SELECT 'Dog',1,1     UNION ALL 
             SELECT 'Cat',27,105  UNION ALL 
             SELECT 'Lizard',83,NULL) 
    SELECT CA.*
    FROM   TableA A 
           FULL OUTER JOIN TableB B 
             ON A.Col1 = B.Col1 
                AND A.Col2 = B.Col2 
    /*Unpivot the joined rows*/
    CROSS APPLY (SELECT 'TableA' AS what, A.* UNION ALL
                 SELECT 'TableB' AS what, B.*) AS CA     
    /*Exclude identical rows*/
    WHERE  EXISTS (SELECT A.* 
                   EXCEPT 
                   SELECT B.*) 
    /*Discard NULL extended row*/
    AND CA.Col1 IS NOT NULL      
    ORDER BY CA.Col1, CA.Col2
    

    给

    what   Col1   Col2        Col3
    ------ ------ ----------- -----------
    TableA Cat    27          86
    TableB Cat    27          105
    TableA Cat    128         92
    TableB Lizard 83          NULL
    

    或处理移动球门柱的版本。

    SELECT DISTINCT CA.*
    FROM   TableA A 
           FULL OUTER JOIN TableB B 
             ON EXISTS (SELECT A.*  INTERSECT  SELECT B.*) 
    CROSS APPLY (SELECT 'TableA' AS what, A.* UNION ALL
                 SELECT 'TableB' AS what, B.*) AS CA     
    WHERE NOT EXISTS (SELECT A.*  INTERSECT  SELECT B.*) 
    AND CA.Col1 IS NOT NULL
    ORDER BY CA.Col1, CA.Col2  
    

    对于具有许多列的表,仍然很难识别不同的特定列。为此,您可以使用以下内容。

    (虽然只是在相对较小的表上,否则这种方法可能不会有足够的性能)

    SELECT t1.primary_key,
           y1.c,
           y1.v,
           y2.v
    FROM   t1
           JOIN t2
             ON t1.primary_key = t2.primary_key
           CROSS APPLY (SELECT t1.*
                        FOR xml path('row'), elements xsinil, type) x1(x)
           CROSS APPLY (SELECT t2.*
                        FOR xml path('row'), elements xsinil, type) x2(x)
           CROSS APPLY (SELECT n.n.value('local-name(.)', 'sysname'),
                               n.n.value('.', 'nvarchar(max)')
                        FROM   x1.x.nodes('row/*') AS n(n)) y1(c, v)
           CROSS APPLY (SELECT n.n.value('local-name(.)', 'sysname'),
                               n.n.value('.', 'nvarchar(max)')
                        FROM   x2.x.nodes('row/*') AS n(n)) y2(c, v)
    WHERE  y1.c = y2.c
           AND EXISTS(SELECT y1.v
                      EXCEPT
                      SELECT y2.v) 
    
    • 17
  3. A-K
    2012-02-10T12:32:44+08:002012-02-10T12:32:44+08:00

    使用 Data Compare 之类的第三方工具很容易完成,或者只是在客户端上完成。在单元测试存储过程的上下文中,我们只是编写了一些 C# 代码。

    这是我们正在使用的 C# 代码,引用自一篇旧文章:关闭那些漏洞 - 测试存储过程

       internal static class DataSetComparer
       {
          internal static bool Compare(DataSet one, DataSet two)
          {
             if(one.Tables.Count != two.Tables.Count)
                return false;
    
             for(int i = 0; i < one.Tables.Count; i++)
                if(!CompareTables(one.Tables[i], two.Tables[i]))
                   return false;
    
             return true;
            }
    
          private static bool CompareTables(DataTable one, DataTable two)
          {
             if(one.Rows.Count != two.Rows.Count)
                return false;
    
             for(int i = 0; i < one.Rows.Count; i++)
                if(!CompareRows(one.Rows[i], two.Rows[i]))
                   return false;
    
             return true;
          }
    
          private static bool CompareRows(DataRow one, DataRow two)
          {
             if(one.ItemArray.Length != two.ItemArray.Length)
                return false;
    
             for(int i = 0; i < one.ItemArray.Length; i++)
                if(!CompareItems(one.ItemArray[i], two.ItemArray[i]))
                   return false;
    
             return true;
          }
    
          private static bool CompareItems(object value1, object value2)
          {
             if(value1.GetType() != value2.GetType())
                return false;
    
             if(value1 is DBNull)
                return true;
    
             if(value1 is DateTime)
                return ((DateTime) value1).CompareTo((DateTime) value2)
                                                                  == 0;
    
             if(value1 is byte[])
             {
                if(((byte[]) value1).Length != ((byte[]) value2).Length)
                   return false;
    
                for(int i = 0; i < ((byte[]) value1).Length; i++)
                   if(((byte[]) value1)[i] != ((byte[]) value2)[i])
                      return false;
    
                return true;
             }
    
             return value1.ToString().Equals(value2.ToString());
          }
       }
    
    • 7
  4. ErikE
    2012-03-23T13:32:00+08:002012-03-23T13:32:00+08:00

    这是一种显示所要求内容的方法:

    SELECT
       Which = 'TableA',
       *
    FROM (
       SELECT * FROM dbo.TableA
       EXCEPT
       SELECT * FROM dbo.TableB
    ) X
    UNION ALL
    SELECT
       'TableB',
       *
    FROM (
       SELECT * FROM dbo.TableB
       EXCEPT
       SELECT * FROM dbo.TableA
    ) X
    ORDER BY
       Col1, Col2, Col3, Col4, Col5, Col6, Col7, Col8, Col9, Col10, Col11, Col12, Col13, Col14, Col15, Col16, Col17, Col18, Col19, Col20, Col21, Col22, Col23, Col24, Col25, Col26, Col27, Col28, Col29, Col30
    ;
    
    • 4

相关问题

  • 死锁的主要原因是什么,可以预防吗?

  • 我在索引上放了多少“填充”?

  • 是否有开发人员遵循数据库更改的“最佳实践”类型流程?

  • 如何确定是否需要或需要索引

  • 从 SQL Server 2008 降级到 2005

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    如何查看 Oracle 中的数据库列表?

    • 8 个回答
  • Marko Smith

    mysql innodb_buffer_pool_size 应该有多大?

    • 4 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    从 .frm 和 .ibd 文件恢复表?

    • 10 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    如何选择每组的第一行?

    • 6 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    pedrosanta 使用 psql 列出数据库权限 2011-08-04 11:01:21 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST
  • Martin Hope
    bernd_k 什么时候应该使用唯一约束而不是唯一索引? 2011-01-05 02:32:27 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve