【发布时间】:2017-06-20 17:42:15
【问题描述】:
我知道这是一个常见问题,并且我已经阅读了一些内容。我想要的是一种基于参考行 id 接收下一个和上一个行 id 的高性能方式(最好在一个查询中)。我在 stackoverflow 找到了很多问题和答案,还有一个有价值的线程,答案非常好 https://stackoverflow.com/a/15992856/1230358。我所拥有的是基于此线程中的答案。
select id from test_1
where (
id = IFNULL((select max(id) from test_1 where id < 2 order by starts_on, id), 0)
or id = IFNULL((select min(id) from test_1 where id > 2 order by starts_on, id), 0)
)
使用引用id=2查询返回的正是我需要的结果(第一行是前一个id,第二行是下一个id):
id
--
1
--
3
问题是,如果查询边缘情况id=1 或id=max(id),结果会错过前一个
或下一行 id,因为根本没有上一行或下一行。结果现在只有一行,不清楚这是否是前一个我们的下一行 id。
id
--
2 (next value)
但是,我需要这样的结果
id
--
NULL (or 0 - previous value)
--
2 (next value)
我需要的是一个基于或类似于上层查询的性能的解决方案,它最好用 NULL 值(或 0)填充不存在的边缘情况 id。由于我正在使用支持不同 dbms 的 web 框架计算结果,它应该适用于 mysql、sqlite 和 postgres。它应该适用于以下架构:
drop table if exists test_1;
create table test_1 (id INTEGER PRIMARY KEY,starts_on DATETIME, ends_on DATETIME);
insert into test_1 (starts_on, ends_on) Values ('2017-01-01 00:00:00', '2017-01-01 00:00:00');
insert into test_1 (starts_on, ends_on) Values ('2017-01-01 00:00:00', '2017-01-01 00:00:00');
insert into test_1 (starts_on, ends_on) Values ('2017-01-01 00:00:00', '2017-01-01 00:00:00');
insert into test_1 (starts_on, ends_on) Values ('2017-01-01 00:00:00', '2017-01-01 00:00:00');
insert into test_1 (starts_on, ends_on) Values ('2017-01-01 00:00:00', '2017-01-01 00:00:00');
insert into test_1 (starts_on, ends_on) Values ('2017-01-01 00:00:00', '2017-01-01 00:00:00');
insert into test_1 (starts_on, ends_on) Values ('2017-01-01 00:00:00', '2017-01-01 00:00:00');
drop table if exists test_2;
create table test_2 (id INTEGER PRIMARY KEY,starts_on DATETIME, ends_on DATETIME);
insert into test_2 (starts_on, ends_on) Values ('2017-01-01 00:00:00', '2017-01-07 00:00:00');
insert into test_2 (starts_on, ends_on) Values ('2017-01-02 00:00:00', '2017-01-08 00:00:00');
insert into test_2 (starts_on, ends_on) Values ('2017-01-03 00:00:00', '2017-01-09 00:00:00');
insert into test_2 (starts_on, ends_on) Values ('2017-01-04 00:00:00', '2017-01-10 00:00:00');
insert into test_2 (starts_on, ends_on) Values ('2017-01-05 00:00:00', '2017-01-11 00:00:00');
insert into test_2 (starts_on, ends_on) Values ('2017-01-06 00:00:00', '2017-01-12 00:00:00');
insert into test_2 (starts_on, ends_on) Values ('2017-01-07 00:00:00', '2017-01-13 00:00:00');
drop table if exists test_3;
create table test_3 (id INTEGER PRIMARY KEY,starts_on DATETIME, ends_on DATETIME);
insert into test_3 (starts_on, ends_on) Values ('2017-01-01 00:00:00', '2017-01-07 00:00:00');
insert into test_3 (starts_on, ends_on) Values ('2017-01-02 00:00:00', '2017-01-08 00:00:00');
insert into test_3 (starts_on, ends_on) Values ('2017-01-02 00:00:00', '2017-01-09 00:00:00');
insert into test_3 (starts_on, ends_on) Values ('2017-01-04 00:00:00', '2017-01-10 00:00:00');
insert into test_3 (starts_on, ends_on) Values ('2017-01-05 00:00:00', '2017-01-11 00:00:00');
insert into test_3 (starts_on, ends_on) Values ('2017-01-07 00:00:00', '2017-01-12 00:00:00');
insert into test_3 (starts_on, ends_on) Values ('2017-01-07 00:00:00', '2017-01-13 00:00:00');
更新:
一个可能的解决方案是:
select distinct
(select max(id) from test_1 where id < 7 order by starts_on, id) as prev,
(select min(id) from test_1 where id > 7 order by starts_on, id) as next
from test_1
【问题讨论】:
-
什么是 dbms?
-
抱歉忘记提了。应该是 mysql、sqlite 和 postgres。
-
窗口函数是标准 SQL,但与 SQLite 使用的标准版本不同。
-
知道了@CL。使用标准,我认为我在表达它适用于每个主要的数据库平台。我的坏
标签: mysql sql postgresql sqlite django-models