PostgreSQL:检测结果集的第一行/最后一行
有没有办法在select中嵌入一个标志,指示它是结果集的第一行或最后一行?我在想一些事情,大意是:PostgreSQL:检测结果集的第一行/最后一行,postgresql,select,window-functions,Postgresql,Select,Window Functions,有没有办法在select中嵌入一个标志,指示它是结果集的第一行或最后一行?我在想一些事情,大意是: > SELECT is_first_row() AS f, is_last_row() AS l FROM blah; f | l ----------- t | f f | f f | f f | f f | t 答案可能是肯定的,但我只是刚刚了解了它们,我质疑它们的效率 SELECT first_value(unique_column)
> SELECT is_first_row() AS f, is_last_row() AS l FROM blah;
f | l
-----------
t | f
f | f
f | f
f | f
f | t
答案可能是肯定的,但我只是刚刚了解了它们,我质疑它们的效率
SELECT first_value(unique_column) OVER () = unique_column, last_value(unique_column) OVER () = unique_column, * FROM blah;
似乎做了我想做的事。不幸的是,我甚至不完全理解这种语法,但由于unique_列是惟一的,并且不是NULL,所以它应该提供明确的结果。但如果真的进行了分类,那么治疗可能比疾病更糟糕。事实上,在我的测试中,unique_列没有排序,所以这就是问题所在
解释分析并不表明存在效率问题,但它什么时候告诉过我需要知道什么
我可能需要在聚合函数中使用它,但我刚刚被告知窗口函数在那里是不允许的 试用
SELECT columns
FROM mytable
Join conditions
WHERE conditions ORDER BY date DESC LIMIT 1
UNION ALL
SELECT columns
FROM mytable
Join conditions
WHERE conditions ORDER BY date ASC LIMIT 1
选择“仅削减一半处理时间”。您也可以使用索引。事实上,窗口函数是一种很好的方法,对于您的需求来说,它们非常棒 关于效率,窗口函数在现有的数据集上工作。这意味着DBMS只需添加额外的处理来推断第一个/最后一个值 我只想建议一件事:我想在OVER子句中放入ORDER BY条件,以确保多个执行之间的数据集顺序相同,从而向您返回相同的值。您可以在appropiate窗口上使用lead和lag窗口函数,并将它们与NULL进行比较: -\i tmp.sql
CREATE TABLE ztable
( id SERIAL PRIMARY KEY
, starttime TIMESTAMP
);
INSERT INTO ztable (starttime) VALUES ( now() - INTERVAL '1 minute');
INSERT INTO ztable (starttime) VALUES ( now() - INTERVAL '2 minute');
INSERT INTO ztable (starttime) VALUES ( now() - INTERVAL '3 minute');
INSERT INTO ztable (starttime) VALUES ( now() - INTERVAL '4 minute');
INSERT INTO ztable (starttime) VALUES ( now() - INTERVAL '5 minute');
INSERT INTO ztable (starttime) VALUES ( now() - INTERVAL '6 minute');
SELECT id, starttime
, ( lead(id) OVER www IS NULL) AS is_first
, ( lag(id) OVER www IS NULL) AS is_last
FROM ztable
WINDOW www AS (ORDER BY id )
ORDER BY id
;
SELECT id, starttime
, ( lead(id) OVER www IS NULL) AS is_first
, ( lag(id) OVER www IS NULL) AS is_last
FROM ztable
WINDOW www AS (ORDER BY starttime )
ORDER BY id
;
SELECT id, starttime
, ( lead(id) OVER www IS NULL) AS is_first
, ( lag(id) OVER www IS NULL) AS is_last
FROM ztable
WINDOW www AS (ORDER BY starttime )
ORDER BY random()
;
结果:
[更新:添加了一个随机排序的案例]使用窗口函数非常简单,特别是: 如您所见,无界前一行和当前行之间的行数*返回从数据集开始到当前行的行数,当前行和无界后一行之间的行数*返回从当前到数据集结束的行数。1表示第一行/最后一行 它会一直工作,直到您按顺序对数据集进行排序为止。在这种情况下,需要在帧定义中复制它:
with t(x, y) as (select generate_series(1,5), random())
select *,
count(*) over (order by y rows between unbounded preceding and current row),
count(*) over (order by y rows between current row and unbounded following)
from t order by y;
┌───┬───────────────────┬───────┬───────┐
│ x │ y │ count │ count │
├───┼───────────────────┼───────┼───────┤
│ 1 │ 0.125781774986535 │ 1 │ 5 │
│ 4 │ 0.25046408502385 │ 2 │ 4 │
│ 5 │ 0.538880597334355 │ 3 │ 3 │
│ 3 │ 0.802807193249464 │ 4 │ 2 │
│ 2 │ 0.869908029679209 │ 5 │ 1 │
└───┴───────────────────┴───────┴───────┘
注:正如一匹没有名字的马所说:
没有排序就没有第一行或最后一行
知道第一条和最后一条记录的目的是什么?你想用它做什么?是的,窗口函数是解决此类问题的最佳方法。如果需要聚合,只需将第一个查询的结果用作聚合查询中的表,然后它就可以正常工作。结果集将异步发送到另一个系统,该系统希望知道它正在查看结果集的哪一部分。在生成结果集之后应用这些符号是很困难的。关系数据库中没有第一行或最后一行这样的东西。表中的行不会以任何方式排序。因此,除非指定排序定义,否则无法判断第一行是什么。您有一个空窗口定义:OVER,这意味着:一切正常!。与我的答案中的窗口定义相比,它确实强加了一个顺序。@Opux,老实说,我认为你把事情复杂化了很多。如果你不订购记录,那么第一个和最后一个是完全随机的。更重要的是,当它转到另一个系统时,它可以以完全不同的顺序读取,而不是在您的语句中。您将只有两条记录被标记为数百条、数千条或数百万条记录中的首末条记录。有用性接近于零,或者我错过了一些非常重要的东西,我不明白你为什么要这样做。是的,但是,这就是排序,如果可能的话,这是我想要避免的事情。好了,窗口函数不需要排序reference,@Opux:没有排序就没有第一行或最后一行。而窗口函数——如果你正确使用它们——也需要排序——第一个选择应该是什么?数据似乎是错误的。看来我还需要整理一下。我尝试从中删除ORDER BY,但数据也是错误的。我添加了一个额外的查询以说明结果不依赖于排序顺序。我的期望是第一条记录将被称为first,最后一条记录将被称为last。对于耶稣马太福音20:16,第一个问题是好的。但是第二个给出了正确的结果,但是排序第一个/最后一个决定是根据窗口定义做出的,结果的最终顺序是不相关的。[和:除了排序,查询2和查询3的结果是相同的。我刚刚编辑了我的问题,设置了一个新的路障。也许这能让我更清楚地了解我要完成的任务。看起来你对排序的看法是正确的。我刚刚编辑了我的问题,添加了一个新的发展。如果我需要排序,那么我认为这件事不值得去做。我的下一步是你要更好地理解一遍,以防它提供了一个解决方案。这似乎也很有效。不过有点罗嗦。我只是幸运地发现第一个\u valueunique\u column OVER=unique\u column对我有效,而且它
可能在下面的某个地方不起作用?我发现,如果我进行排序,那么我可以通过将主查询放入子查询,然后将第一个值放入superquery,从而使其工作。@Opux这是一篇很棒的文章,详细解释了窗口函数的工作原理:
with t(x, y) as (select generate_series(1,5), random())
select *,
count(*) over (rows between unbounded preceding and current row),
count(*) over (rows between current row and unbounded following)
from t;
┌───┬───────────────────┬───────┬───────┐
│ x │ y │ count │ count │
├───┼───────────────────┼───────┼───────┤
│ 1 │ 0.543995119165629 │ 1 │ 5 │
│ 2 │ 0.886343683116138 │ 2 │ 4 │
│ 3 │ 0.124682310037315 │ 3 │ 3 │
│ 4 │ 0.668972567655146 │ 4 │ 2 │
│ 5 │ 0.266671542543918 │ 5 │ 1 │
└───┴───────────────────┴───────┴───────┘
with t(x, y) as (select generate_series(1,5), random())
select *,
count(*) over (order by y rows between unbounded preceding and current row),
count(*) over (order by y rows between current row and unbounded following)
from t order by y;
┌───┬───────────────────┬───────┬───────┐
│ x │ y │ count │ count │
├───┼───────────────────┼───────┼───────┤
│ 1 │ 0.125781774986535 │ 1 │ 5 │
│ 4 │ 0.25046408502385 │ 2 │ 4 │
│ 5 │ 0.538880597334355 │ 3 │ 3 │
│ 3 │ 0.802807193249464 │ 4 │ 2 │
│ 2 │ 0.869908029679209 │ 5 │ 1 │
└───┴───────────────────┴───────┴───────┘