我有一个简单的表格如下
SQL> select * from test;
ID STUFF
---------- ------------------------------------------------------------
1 a
2 b
3 c
4 d
5 e
6 f
7 g
7 rows selected.
我想构建一个返回如下内容的查询:
STUFF A STUFF B
---------- --------------------------------------
a e
b f
c g
d NULL
即,取两个由id确定的范围,用NULL填充缺失值。范围是连续的,可以重叠,并且长度不同。
这可能吗?如果是,那么查询是什么?
临时表sql:
CREATE TABLE test(id number, stuff VARCHAR(20));
INSERT INTO test VALUES (1, 'a');
INSERT INTO test VALUES (2, 'b');
INSERT INTO test VALUES (3, 'c');
INSERT INTO test VALUES (4, 'd');
INSERT INTO test VALUES (5, 'e');
INSERT INTO test VALUES (6, 'f');
INSERT INTO test VALUES (7, 'g');
答案 0 :(得分:1)
select a.stuff as stuffa, b.stuff as stuffb
from test as a
left join test as b
on (a.id-:minida) = (b.id-:minidb)
and b.id between :minidb and :maxidb
where a.id between :minida and :maxida
(其中冒号表示绑定到预准备语句的值的标识符)应该在(maxidb-minidb) <= (maxida-minida)
时有效。但这不能以完全对称的方式工作(其中任何一个范围可能比另一个范围大)。
你描述的一个完全对称的查询无疑可以写成一个非常繁琐的UNION,基本上重复每个部分(通过适当的交换)并将上面的<=
表达式作为条件第一次添加,同样但是>
而不是第二次(不对称,如果范围相等;-),那么联盟的两半中的一半保证是空的,但我必须得到严重补偿的单调乏味实际写出所说的联盟; - )。
如果您最喜欢的SQL方言支持FULL OUTER JOIN,那么这可能会有所帮助......但是许多方言,例如MySQL和SQLite,都不支持FULL版本。
答案 1 :(得分:0)
我很难绕过你想要做的事情。但是这个陈述将适用于你给出的例子。希望这能为您指出更通用的解决方案。
select stuff as stuffa,(select top 1 stuff from test where id >= t.id + 4 )stuffb from test t where t.Id<=4
答案 2 :(得分:0)
@Alex 干得好。我回应你对产生对称结果的单调乏味的担忧。不要打扰。如果这个简单的例子变得复杂,它将成为生产代码的噩梦(更不用说比较两个以上范围的可能性)。
@tetra 基本上任何有效的id范围。在部署之前,范围的长度和位置是未知的。
@Everyone 优选整洁的溶液,“不能整齐地完成”是一种很好的解决方案。我可以告诉客户,“它无法完成”。