我试图比较两个表,SQL Server,以验证一些数据。我想从两个表中返回数据在其中一个或另一个中的所有行。本质上,我想展示所有的差异。我需要检查这样做的三段数据,FirstName, LastName和产品。

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

这基本上会告诉我测试数据中哪些是真实数据中没有的。这完全可以满足我的需求。


当前回答

对于一个简单的冒烟测试,你试图确保两个表匹配w/out担心列名:

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

您可以很容易地编写一个存储过程来比较一批表。

其他回答

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

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

有很多这样的工具,如ApexSQL Data Diff或Quest Toad,你可以在试用模式下使用它们来完成工作。

如果你有表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的列将为NULL。

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

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

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

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

EXCEPT和NOT EXISTS是快速发现数据集之间差异的好方法,但我经常想知道哪些列是不同的,以及它们是如何不同的。

在这些情况下,我发现有用的方法是使用UNPIVOT将列转换为可以逐行比较的键值对。

不过,为了有用,需要有一种方法来匹配你想要比较的记录,在你的例子中,比如社会安全号码或“个人id”:

CREATE TABLE [RealData] 
(
  [PersonId] INT,
  [FirstName] NVARCHAR(100), 
  [LastName] NVARCHAR(100),
  [ProductName] NVARCHAR(100)
)

CREATE TABLE [TempTestData] 
(
  [PersonId] INT,
  [FirstName] NVARCHAR(100), 
  [LastName] NVARCHAR(100),
  [ProductName] NVARCHAR(100)
)

INSERT INTO [RealData] ([PersonId], [FirstName], [LastName], [ProductName])
VALUES 
(1, 'Al', 'Bundy', 'Ladies Size 12'),
(2, 'Peggy', 'Bundy', 'TV Guide')

INSERT INTO [TempTestData] ([PersonId], [FirstName], [LastName], [ProductName])
VALUES 
(1, 'Al', 'Bundy', 'Ladies Size 13'),
(2, 'Peggy', 'Bundy', 'TV Guide')

UNPIVOT加上一些cte

;WITH RealDataCte AS (
  SELECT 
   'Real Data' AS [DataSource],
   unpivotedRealData.* 
  FROM
    (SELECT 
      CAST([PersonId] AS NVARCHAR(100)) AS [PersonId],
      [FirstName],
      [LastName], 
      [ProductName]
    FROM [RealData]) AS realData
  UNPIVOT
  (ColumnValue FOR ColumnName IN ([FirstName], [LastName],  [ProductName])) AS unpivotedRealData
),
TempTestDataCte AS (
  SELECT 
    'Temp Test Data' AS [DataSource],
     unpivotedDempTestData.* 
  FROM
    (SELECT 
      CAST([PersonId] AS NVARCHAR(100)) AS [PersonId],
      [FirstName],
      [LastName], 
      [ProductName]
    FROM [TempTestData]) AS tempTestData
  UNPIVOT
  (ColumnValue FOR ColumnName IN ([FirstName], [LastName],  [ProductName])) AS unpivotedDempTestData
)
SELECT
  RealDataCte.[DataSource],
  RealDataCte.[ColumnName],
  RealDataCte.[ColumnValue],
  TempTestDataCte.[DataSource],
  TempTestDataCte.[ColumnName],
  TempTestDataCte.[ColumnValue],
  CASE WHEN RealDataCte.[ColumnValue] <> TempTestDataCte.[ColumnValue] THEN 'YES' ELSE 'NO' END AS ColumnsDiffer
FROM RealDataCte
INNER JOIN
TempTestDataCte 
ON RealDataCte.[ColumnName] = TempTestDataCte.[ColumnName] 
AND RealDataCte.[PersonId] = TempTestDataCte.[PersonId] 
WHERE 
RealDataCte.[ColumnValue] <> TempTestDataCte.[ColumnValue] 

结果-两种产品是不同的:

如果要在大量的行中比较很多很多列,这是非常好的。

不过,它可能需要一段时间来设置,并且您确实需要将每个列值转换为相同的类型,这可能需要一段时间(注意PersonId的CAST)。

如果数据集非常大,您可能还想使用临时表而不是cte。

SQL小提琴示例