自连接不包括将行连接到自身

问题描述 投票:0回答:2

有时您需要表中的所有行对:其与自身的笛卡尔积。 这可以通过连接来完成。

drop table if exists #a
create table #a (x int)
insert into #a values (1),(2),(3)
select *
from #a a1
join #a a2
  on 0 = 0 -- always-true join condition

这给出了九行。

如果我想获得除了行与自身配对以外的对,我可以添加一个需要不同 x 值的连接条件:

select *
from #a a1
join #a a2
  on a1.x != a2.x

结果中只给出了六行。 但我假设列 x 是唯一标识符。 假设不是:

delete from #a
insert into #a values (4), (4), (5)

表中有两行保存值 4。它们具有相同的值,但仍然是单独的行,并且 SQL 有时允许您单独处理它们(例如使用

set rowcount 1 update #a set x = 40 where x = 4 set rowcount 0
)。 我仍然想从自连接中获取所有行对,但排除行与自身配对的行对。 所以我想要的输出是
(4, 4), (4, 5), (4, 4), (4, 5), (5, 4), (5, 4)
。 输出中仍有六行。

我找到了一个可能的答案,我将发布它。 (当然,有诸如“添加第二列”或“确保列 x 具有唯一值”之类的答案,或者当然“不要尝试制作笛卡尔积”,但我有兴趣了解哪些设施T-SQL 提供。)

sql-server t-sql join self-join sql-server-2019
2个回答
0
投票
select *
from #a a1
join #a a2
  on a1.%%physloc%% != a2.%%physloc%%

这个

%%physloc%%
是 Oracle 的
rownum
的松散等效项,并以某种方式给出磁盘上行的标识。 但是,尽管在 Oracle 中看到基于
rownum
的查询相当常见,但在 MSSQL 上我直到现在才遇到过
%%physloc%%

根据评论Can %%physloc%% 用作即时查询的行标识符或键吗?即使在执行查询时,行的“位置”也可能会发生变化,因此这不是“可靠的技术。


0
投票

相关问题ROWNUM作为T-SQL中的伪列等效项?建议使用此解决方案

with t as (select *, row_number() over (order by (select null)) as rownum from #a)
select *
from t a1
join t a2
  on a1.rownum != a2.rownum

检查实际的查询计划(诚然在这个小玩具表上)表明这不会引入任何额外的排序步骤,因此应该相当快,尽管可能不如 Oracle 提供的本机

rownum
快。

© www.soinside.com 2019 - 2024. All rights reserved.