Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/user-interface/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
PostgreSQL:检测结果集的第一行/最后一行_Postgresql_Select_Window Functions - Fatal编程技术网

PostgreSQL:检测结果集的第一行/最后一行

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中嵌入一个标志,指示它是结果集的第一行或最后一行?我在想一些事情,大意是:

> 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 │
└───┴───────────────────┴───────┴───────┘