3

我有两个表(OriginalLoad),我想使用存储过程比较它们。

数据库是 SQL Server 2008。

这是我的示例 SP:

USE [TestDB]
GO

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

CREATE PROCEDURE [dbo].[ValidateLoad] 
AS 
    SET nocount ON; 

    IF EXISTS(SELECT * 
              FROM   dbo.original 
              EXCEPT 
              SELECT * 
              FROM   dbo.LOAD) 
      BEGIN 
          PRINT 
      'Warning! The following information has not been loaded' 

       PRINT '---------------------------------' 

       PRINT 'Load result: Fail' 

          SELECT * 
          FROM   dbo.original 
          EXCEPT 
          SELECT * 
          FROM   dbo.LOAD 

      set noexec on
      END 

    IF EXISTS(SELECT * 
              FROM   dbo.LOAD 
              EXCEPT 
              SELECT * 
              FROM   dbo.original) 
      BEGIN 
          PRINT 
      'Warning! The following information does not exist in Original table' 

       PRINT '---------------------------------' 

       PRINT 'Load result: Fail' 

    SELECT * 
    FROM   dbo.LOAD 
    EXCEPT 
    SELECT * 
    FROM   dbo.original 

    set noexec on
END 

    PRINT 'Load result: Succeeded' 

我觉得效率不是很高。

我的目的是验证这两个表/数据集是否相同,如果不是,则输出结果并带有有意义的错误消息。

任何想法?

谢谢你。

4

3 回答 3

0

假设您至少有一个具有 NOT NULL 约束的列 c1,那么此查询应该为您提供任一表中缺少的所有行的列表:

SELECT t1.*,t2.* 
FROM dbo.original t1 full outer join dbo.LOAD t2
ON (list of join keys)
WHERE t1.c1 IS NULL or t2.c1 IS NULL

不过,不确定它与基于 EXCEPT 的查询相比效率如何,您需要尝试一下。

于 2012-11-19T23:32:49.477 回答
0

您是否考虑过使用合并语句比较两者。

当不匹配时插入#temp。然后您可以显示临时表的结果。

于 2012-11-19T22:25:00.077 回答
0

一般情况下的回答:

SELECT * FROM tableA
UNION 
SELECT * FROM tableB
EXCEPT 
SELECT * FROM tableA 
INTERSECT
SELECT * FROM tableB;

详细解答:

问:字母 SQL 代表什么?A. 几乎没有资格作为一门语言...... ROFL 但请考虑以下严重问题:

CREATE TABLE MyTable
   ( ID INTEGER NOT NULL UNIQUE, data_col VARCHAR(10) NOT NULL );

DECLARE @MyTable TABLE 
   ( ID INTEGER NOT NULL UNIQUE, data_col VARCHAR(10) NOT NULL );

现在提问:

问:在语言(计算机科学)术语中,是@MyTable一个变量吗?一口井...

问题 1:无法将表值分配给@MyTableeg

-- Assignment attempt 1:
SET @MyTable = MyTable;  -- COMPILE ERROR

-- Assignment attempt 2:
SET @MyTable = ( VALUES ( 1, NULL ), ( 2, '' ), ( 3, 'Test' ) );  -- COMPILE ERROR

问题 2:无法比较变量,例如

-- Comparison attempt 1:
IF ( @MyTable = @MyTable ) BEGIN; 
    PRINT 'Tables are the same.' 
END;  -- COMPILE ERROR

-- Comparison 2:
IF ( @MyTable = ( VALUES ( 1, NULL ), ( 2, '' ), ( 3, 'Test' ) ) ) BEGIN; 
    PRINT 'Tables are the same.' 
END;  -- COMPILE ERROR

...所以我们必须相信 @MyTable 是一个既不支持赋值也不支持比较的“变量”。

问:如果@MyTable是一个变量,在语言(计算机科学)术语中是MyTable什么?A. 常数?价值?类型?班级?结构?以上都不是?

...是的,SQL 确实是一种非常奇怪的语言!

问:什么是关系运算符?A. 在关系模型中,它是一个以两个关系值作为参数并返回一个关系值作为结果的运算符。

问:SQL 是否支持关系运算符?答:不完全是。SQL 确实具有真正关系语言的用户所熟悉的运算符(UNIONINTERSECTEXCEPT等)。但是,SQL 支持非关系特性,最显着的是空值、重复行和重复列名。因此,需要非常小心地确保这些运算符的参数和结果等价于关系。

Q 如何使用 SQL 的“关系式”运算符比较两个表的相等性?A 这是一种方法:

SELECT * FROM tableA
UNION 
SELECT * FROM tableB
EXCEPT 
SELECT * FROM tableA 
INTERSECT
SELECT * FROM tableB;

测试以证明上述内容(注意以下并非所有关系值,但确实证明了运算符在 SQL 空值上的逻辑工作):

示例 1:表相同(期望零行 == PASS):

WITH tableA AS
     ( SELECT * FROM ( VALUES ( 1, NULL ), 
                              ( 2, '' ), 
                              ( 3, 'Test' )
                     ) AS T ( ID, data_col ) ),
     tableB AS
     ( SELECT * FROM ( VALUES ( 1, NULL ), 
                              ( 2, '' ), 
                              ( 3, 'Test' )
                     ) AS T ( ID, data_col ) )
SELECT * FROM tableA
UNION 
SELECT * FROM tableB
EXCEPT 
SELECT * FROM tableA 
INTERSECT
SELECT * FROM tableB;

示例 2:tableB 是 tableB 的真子集(期望行 == FAIL):

WITH tableA AS
     ( SELECT * FROM ( VALUES ( 1, NULL ), 
                              ( 2, '' ), 
                              ( 3, 'Test' )
                     ) AS T ( ID, data_col ) ),
     tableB AS
     ( SELECT * FROM ( VALUES ( 1, NULL ), 
                              ( 2, '' ) 
                     ) AS T ( ID, data_col ) )
SELECT * FROM tableA
UNION 
SELECT * FROM tableB
EXCEPT 
SELECT * FROM tableA 
INTERSECT
SELECT * FROM tableB;

示例 3:tableA 是 tableB 的真子集(期望行 == FAIL):

WITH tableA AS
     ( SELECT * FROM ( VALUES ( 1, NULL ), 
                              ( 3, 'Test' )
                     ) AS T ( ID, data_col ) ),
     tableB AS
     ( SELECT * FROM ( VALUES ( 1, NULL ), 
                              ( 2, '' ), 
                              ( 3, 'Test' )
                     ) AS T ( ID, data_col ) )
SELECT * FROM tableA
UNION 
SELECT * FROM tableB
EXCEPT 
SELECT * FROM tableA 
INTERSECT
SELECT * FROM tableB;

示例 4:tableA 和 tableB 有一些但不是所有的共同行值(期望行 == FAIL):

WITH tableA AS
     ( SELECT * FROM ( VALUES ( 1, NULL ), 
                              ( 4, 'Lone' )
                     ) AS T ( ID, data_col ) ),
     tableB AS
     ( SELECT * FROM ( VALUES ( 1, NULL ), 
                              ( 4, 'Sole' )
                     ) AS T ( ID, data_col ) )
SELECT * FROM tableA
UNION 
SELECT * FROM tableB
EXCEPT 
SELECT * FROM tableA 
INTERSECT
SELECT * FROM tableB;

示例 5:tableA 和 tableB 没有共同的行值(期望行 == FAIL):

WITH tableA AS
     ( SELECT * FROM ( VALUES ( 5, NULL ), 
                              ( 6, 'Different' )
                     ) AS T ( ID, data_col ) ),
     tableB AS
     ( SELECT * FROM ( VALUES ( 7, NULL ), 
                              ( 8, 'Not the same' )
                     ) AS T ( ID, data_col ) )
SELECT * FROM tableA
UNION 
SELECT * FROM tableB
EXCEPT 
SELECT * FROM tableA 
INTERSECT
SELECT * FROM tableB;

问:为什么 SQL Server DBA 倾向于不使用这种语法,而更喜欢使用FULL OUTER JOIN. A. 可能出于多种原因,例如熟悉遗留语法(例如EXCEPT在 SQL Server 2005 中引入)。但最有可能的是,SQL DBA 倾向于编写他们认为最有效的查询(贬义,过早优化)。确实,SQL Server 优化器不能很好地处理运算符INTERSECTEXCEPT.

问:为什么更喜欢“关系型”运算符?A. 因为它们不那么冗长并且可以说更容易阅读。这两个都是测试代码的好品质。

于 2013-02-19T11:45:02.470 回答