Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/26.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 选择仅出现在两个表之一中的数据的最佳方法是什么?_Sql_Sql Server_Sql Server 2005_Select - Fatal编程技术网

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

Sql 选择仅出现在两个表之一中的数据的最佳方法是什么?,sql,sql-server,sql-server-2005,select,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 VA

如果我有两张这样的表格:

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
在这种情况下,艾伦、弗雷德和史蒂夫都会回来

但这些感觉真的很笨重-有没有更有效的方法来实现这一点?

您可以使用并相交:

不确定这是否比你的例外和联合示例更好

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  
完全外部联接保证联接两侧的记录。无论什么记录,如果你要查找的记录两边都没有,那么它的一边或另一边都将是空的。这就是我们筛选空值的原因

合并是为了保证显示非空值

最后,值得强调的是,重复是通过ID检测的。如果您希望它也是通过名称检测的,您应该将名称添加到联接中。如果您只想按姓名加入,请仅按姓名加入。这个使用JOIN的解决方案为您提供了这种灵活性


顺便说一句,由于您提供了创建和插入代码,我实际上运行了它们,上面的代码完全可以工作。

感谢您的解释-这会不会在较大的表/多列上存在可伸缩性问题?我的实际表大约有200-1000万行,每行最多有15列左右,我认为交叉连接会让事情变得有点慢?如果在连接字段上有索引,那么性能会比使用EXCEPT和INTERSECT好得多。如果我在多个列上连接,我需要在所有连接列上都有一个覆盖索引,或者有很多单列索引可以吗?@Adrian:难怪。连接通常在几列上完成,而UNION等人检查所有列。嗯,我不是索引专家,但我相信您应该从一个索引开始,为所有连接字段创建索引。既然你手头有数据,你就有了一位伟大的老师:尝试与错误。实验在那里学习了很多!
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
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