比较同一字段中两个(或更多)范围内的数据

时间:2009-07-15 03:13:53

标签: sql

我有一个简单的表格如下

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');

3 个答案:

答案 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 优选整洁的溶液,“不能整齐地完成”是一种很好的解决方案。我可以告诉客户,“它无法完成”。