3

这是初始数据:

CREATE TABLE #data
    (
    Id integer,
    Surname varchar(50),
    DOB datetime
    )   
INSERT INTO #data
values 
(1,'smith', null),
(2,'jones', '01 jan 1970'),
(3,'vernon', null),
(4,'smith', '01 jan 1970'),
(5,'jones', '01 jan 1970'),
(6,'vernon', '01 jan 1970'),
(7,null, '01 jan 1970') 

以下是排除列表:

CREATE TABLE #exclusions
    (
    ExcludedSurname varchar(50),
    ExcludedDOB datetime
    )   
INSERT INTO #exclusions
values 
('smith', '01 jan 1970'),
('jones', '01 jan 1970'),
('vernon', null),
(null, '01 jan 1970')   

这是一个返回我有点意外结果的查询:

SELECT * 
FROM #data a
WHERE
  NOT EXISTS
    (
    SELECT 1
    FROM #exclusions e
    WHERE
            a.DOB = e.ExcludedDOB and
            a.Surname = e.ExcludedSurname
    ) 

为了确保Id排除 s 3 和 7,我可以对脚本进行这种丑陋的更改。生产表中有很多可能的数据(#data 的实时版本是 1000m 条记录)——这就是为什么我选择了这么多的替代品来null.

SELECT * 
FROM #data a
WHERE
  NOT EXISTS
    (
    SELECT 1
    FROM #exclusions e
    WHERE  
            ISNULL(a.DOB, '01 JAN 2200') = ISNULL(e.ExcludedDOB, '01 JAN 2200')  and
            ISNULL(a.Surname,'AAAAAAAAAAAAAAAA') = ISNULL(e.ExcludedSurname,'AAAAAAAAAAAAAAAA')
    )   

这是在SQL Fiddle上

有没有更优雅的方式来完成上述操作?

4

3 回答 3

6

在 PostgreSQL ( SQL Fiddle ) 中,您可以使用

WHERE (a.DOB, a.Surname) IS NOT DISTINCT FROM (e.ExcludedDOB, e.ExcludedSurname)

但是 SQL Server 缺少两个项目才能使其正常工作。行值构造函数IS [NOT] DISTINCT FROM

同时,您可以从这里使用该技术:未记录的查询计划:平等比较

SELECT *
FROM   #data a
WHERE  NOT EXISTS (SELECT *
                   FROM   #exclusions e
                   WHERE  EXISTS (SELECT a.DOB,
                                         a.Surname
                                  INTERSECT
                                  SELECT e.ExcludedDOB,
                                         e.ExcludedSurname)) 

上述用途的变体EXCEPT(现场示例HERE):

SELECT *
FROM   #data a
WHERE  EXISTS (SELECT a.DOB, 
                      a.Surname
               EXCEPT
               SELECT e.ExcludedDOB, 
                      e.ExcludedSurname 
               FROM #exclusions e)  
于 2013-01-05T15:01:13.707 回答
2

@马丁史密斯

看看这个替代方案:

SELECT *
FROM   #data a
WHERE  EXISTS(SELECT a.Surname,
                     a.DOB
              EXCEPT
              SELECT e.ExcludedSurname,
                     e.ExcludedDOB
              FROM   #exclusions e) 

非常优雅和可读。


虽然为什么要打扰上面的 EXISTS 似乎除了所有的工作?

SELECT Surname,
       DOB
FROM   #data
EXCEPT
SELECT ExcludedSurname,
       ExcludedDOB
FROM   #exclusions 

[提供给我的一个朋友——不幸的是,他没有贡献SO——我不知道]

两种选择都在SQL FIDDLE上

于 2013-01-07T16:06:43.897 回答
1

如果您的排除项没有重复项,请不要将其表述为left outer join至少看起来更干净:

SELECT * 
FROM #data a left outer join
     #exclusions e
     on a.DOB = e.ExcludedDOB and
        a.Surname = e.ExcludedSurname
where e.ExcludedDOB is NULL and e.ExcludedSurname is null

然后,您可以使用 a 或逻辑处理 NULL coalesce(此示例同时显示两者):

SELECT * 
FROM #data a left outer join
     #exclusions e
     on (a.DOB = e.ExcludedDOB or a.DOB is NULL and e.ExcludedDOB is NULL) and
        (coealesce(a.Surname, '<null>') = coalesce(e.ExcludedSurname, '<null>')
where e.ExcludedDOB is NULL and e.ExcludedSurname is null

所有这些方法的缺点是我认为它们不会利用排除表上的索引。. . 如果桌子很大,这可能是个好主意。一种方法需要两个连接,但解决了这个问题:

SELECT * 
FROM #data a left outer join
     #exclusions e
     on a.DOB = e.ExcludedDOB and
        a.Surname = e.ExcludedSurname left outer join
     #exclusions enull
     on enull.ExcludedSurname is null and a.Surname is NULL and
        enull.ExcludedDOB = a.DOB
where e.ExcludedDOB is NULL and e.ExcludedSurname is null and
      enull.ExcludedDOB is NULL and enull.ExcludedSurname is null

然而,马丁的方法可能仍然是表现最好的。

如果您不需要id来自#data,那么最简单的方法是:

select Surname, Dob
from #data
except (select ExcludedSurname, ExcludedDB from #exceptions)

我经常使用这个结构来进行表格比较。但是,要获取 id,您会遇到连接中的 NULL 问题。

于 2013-01-05T15:26:42.953 回答