选择仅出现在两个表之一中的数据的最佳方法是什么?

时间:2011-08-05 13:27:10

标签: sql sql-server sql-server-2005 select

如果我有两个这样的表:

CREATE TABLE #table1 (id INT, name VARCHAR(10))
INSERT INTO #table1 VALUES (1,'John')
INSERT INTO #table1 VALUES (2,'Alan')
INSERT INTO #table1 VALUES (3,'Dave')
INSERT INTO #table1 VALUES (4,'Fred')
CREATE TABLE #table2 (id INT, name VARCHAR(10))
INSERT INTO #table2 VALUES (1,'John')
INSERT INTO #table2 VALUES (3,'Dave')
INSERT INTO #table2 VALUES (5,'Steve')

我希望看到所有行只出现在其中一个表中,最好的方法是什么?

我能想到的就是:

SELECT * from #table1 except SELECT * FROM #table2
UNION
SELECT * from #table2 except SELECT * FROM #table1

或者类似的东西:

SELECT id,MAX(name) as name  FROM
(
SELECT *,1 as count from #table1 UNION ALL
SELECT *,1 as count from #table2
) data 
group by id
HAVING SUM(count) =1

在这种情况下会回归艾伦,弗雷德和史蒂夫。

但是这些感觉真的很笨重 - 有没有更有效的方法来解决这个问题?

3 个答案:

答案 0 :(得分:6)

select coalesce(t1.id, t2.id)     id,
       coalesce(t1.name, t2.name) name
from   #table1 t1
       full outer join #table2 t2
         on t1.id = t2.id
where  t1.id is null
        or t2.id is null  

完整的外部联接保证了联接两侧的记录。无论双方都没有的记录(你正在寻找的记录)都会在一侧或其他方面有NULL。这就是我们过滤NULL的原因。

COALESCE可以保证显示非NULL值。

最后,值得强调的是ID会检测到重复。如果您希望它也是名称,则应将name添加到JOIN。如果您只想按名称加入,请仅按name加入。此解决方案(使用JOIN)为您提供了灵活性。

顺便说一句,既然您提供了CREATEINSERT代码,我实际运行了它们,上面的代码就是一个完全正常运行的代码。

答案 1 :(得分:2)

您可以使用EXCEPTINTERSECT

-- All rows
SELECT * FROM #table1 
UNION
SELECT * FROM #table2
EXCEPT -- except
(
  -- those in both tables
  SELECT * FROM #table1 
  INTERSECT
  SELECT * FROM #table2
)

不确定这是否比您的EXCEPTUNION示例...

更好

答案 2 :(得分:1)

select id, name
from
 (select *, count(*) over(partition by checksum(*)) as cc
  from (select *
        from #table1
        union all
        select *
        from #table2
       ) as T
 ) as T
where cc = 1