SQL Server除了和ANSI NULLS

时间:2012-12-04 09:24:44

标签: sql sql-server except

我通过用户定义的函数重构了一些视图,我想确保它们是相同的。

我写了一个小脚本来测试这种情况:

SET ANSI_NULLS OFF
GO

SELECT TOP 1000 [DealNumber]
      ,...others
FROM OLD_VIEW
EXCEPT
SELECT TOP 1000 [DealNumber]
            ,...others
  FROM NEW_VIEW

当我应用它时,我获得了许多行作为结果。但是,如果我从任何行中获取DealNumber,并运行以下命令:

SET ANSI_NULLS OFF
GO

SELECT [DealNumber]
      ,...others
FROM OLD_VIEW
WHERE DealNumber = 'MyDealNumber'
EXCEPT
SELECT [DealNumber]
            ,...others
FROM NEW_VIEW
WHERE DealNumber = 'MyDealNumber'

按预期返回空记录集。

作为一种替代方法,我编写了一个函数Test_View_Correctness,它执行前一个测试。但是如果我像这样运行它:

SELECT TOP 1000 [DealNumber] from OLD_VIEW
where DealNumber IN (SELECT a.DealNumber 
                     FROM Test_View_Correctness(DealNumber) as a)

我如何确保其他方法有效?

2 个答案:

答案 0 :(得分:1)

您需要order by一个唯一列列 - 没有SQL 从不保证行顺序,并且查询的两个部分可能会返回完全不同的行的子集:

SELECT ... FROM ( SELECT TOP 1000 [DealNumber],...others 
                  FROM OLD_VIEW 
                  ORDER BY x,y,z ) a
EXCEPT
SELECT ... FROM ( SELECT TOP 1000 [DealNumber],...others
                  FROM NEW_VIEW
                  ORDER BY x,y,z ) b

答案 1 :(得分:0)

这是因为您使用Top 1000来限制Except正在处理的行。 EXCEPT返回左查询中的任何不同值,这些值在右侧查询中也找不到。 你最好使用NOT EXISTS e.g。

SELECT TOP 1000 [DealNumber]
           ,... others
FROM OLD_VIEW
WHERE NOT EXISTS
   (SELECT * FROM NEW_VIEW WHERE OLD_VIEW.[DealNumber] = [DealNumber])

---基于进一步澄清更新

;WITH NV
AS
(
    SELECT *, CHECKSUM(*) as CHK
    FROM NEW_VIEW
),
OV
AS
(
    SELECT *, CHECKSUM(*) AS CHK
)
SELECT *
FROM NV
FULL OUTER JOIN OV
    ON NV.DealNumber = OV.DealNumber
WHERE NV.DealNumber IS NULL -- CATCH missing rows in new view
   OR OV.DealNumber IS NULL -- CATCH extra rows in new view
   OR NV.CHK <> OV.CHK      -- CATCH differing columns in either view