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