PostgreSQL中一行中窗口函数的第一个和最后一个值

时间:2017-06-05 12:11:38

标签: postgresql window-functions

我希望在指定分区的一行中拥有一列的第一个值和第二列的最后一个值。为此,我创建了这个查询:

SELECT DISTINCT
b.machine_id,
batch,
timestamp_sta,
timestamp_stp,
FIRST_VALUE(timestamp_sta) OVER w AS batch_start,
LAST_VALUE(timestamp_stp) OVER w AS batch_end
FROM db_data.sta_stp AS a
JOIN db_data.ll_lu AS b
ON a.ll_lu_id=b.id
WINDOW w AS (PARTITION BY batch, machine_id ORDER BY timestamp_sta)
ORDER BY timestamp_sta, batch, machine_id;

但正如您在图片中看到的那样,batch_end列中返回的数据不正确。

batch_start 列具有正确的 timestamp_sta 列的第一个值。但是 batch_end 应该是" 2012-09-17 10:49:45"它等于同一行的 timestamp_stp

为什么会这样?

enter image description here

3 个答案:

答案 0 :(得分:6)

@ŁukaszKamiński给出的解释解决了问题的核心。

但是,googleImageButton.setOnClickListener(googleImageButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //action } });) 应替换为last_value。您按max()排序,因此最后一个值是timestamp_sta最大的值,可能与timestamp_sta有关,也可能与timestamp_stp无关。我也会按这两个字段排序。

SELECT DISTINCT
  b.machine_id,
  batch,
  timestamp_sta,
  timestamp_stp,
  FIRST_VALUE(timestamp_sta) OVER w AS batch_start,
  MAX(timestamp_stp) OVER w AS batch_end
FROM db_data.sta_stp AS a
JOIN db_data.ll_lu AS b
ON a.ll_lu_id=b.id
WINDOW w AS (PARTITION BY batch, machine_id 
             ORDER BY timestamp_sta,timestamp_stp 
             RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
ORDER BY timestamp_sta, batch, machine_id;

http://rextester.com/UTDE60342

答案 1 :(得分:6)

这个问题很老,但是这个解决方案比到目前为止发布的解决方案更简单,更快捷:

SELECT b.machine_id
     , batch
     , timestamp_sta
     , timestamp_stp
     , min(timestamp_sta) OVER w AS batch_start
     , max(timestamp_stp) OVER w AS batch_end
FROM   db_data.sta_stp a
JOIN   db_data.ll_lu   b ON a.ll_lu_id = b.id
WINDOW w AS (PARTITION BY batch, b.machine_id) -- No ORDER BY !
ORDER  BY timestamp_sta, batch, machine_id; -- why this ORDER BY?

如果将 ORDER BY 添加到窗口框架定义中,则每个带有较大的ORDER BY表达式的下一行将以更高的帧开始。 min()first_value()都无法返回整个分区的“第一个”时间戳。没有ORDER BY,同一分区的所有行都是 peers ,您将获得所需的结果。

您添加的ORDER BY 有效(不是窗口框架定义中的一个,外部的),但是似乎没有任何意义,并且使查询更昂贵。您可能应该使用与您的窗口框架定义一致的ORDER BY子句,以避免额外的排序费用:

... 
ORDER BY batch, b.machine_id, timestamp_sta, timestamp_stp

在此查询中,我看不到需要DISTINCT。您可以根据需要添加它。或DISTINCT ON ()。但是ORDER BY子句变得更加重要。参见:

如果您需要同一行中的其他一些列(同时仍按时间戳进行排序),则可以使用FIRST_VALUE()LAST_VALUE()来实现。您可能需要将此附加到窗口框架定义 then

ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING

请参阅:

答案 2 :(得分:3)

来自syntax documentation

  

frame_clause指定构成窗口框架的行集,它是当前分区的子集,用于那些作用于框架而不是整个分区的窗口函数。帧可以在RANGE或ROWS模式下指定;在任何一种情况下,它都从frame_start运行到frame_end。 如果省略frame_end,则默认为CURRENT ROW

     

UNBOUNDED PRECEDING的frame_start意味着框架以分区的第一行开始,同样,UNBOUNDED FOLLOWING的frame_end意味着框架以分区的最后一行结束。

function list

  

last_value(value any)返回在窗口框架的最后一行

的行评估的值

所以正确的SQL应该是:

SELECT DISTINCT
b.machine_id,
batch,
timestamp_sta,
timestamp_stp,
FIRST_VALUE(timestamp_sta) OVER w AS batch_start,
LAST_VALUE(timestamp_stp) OVER w AS batch_end
FROM db_data.sta_stp AS a
JOIN db_data.ll_lu AS b
ON a.ll_lu_id=b.id
WINDOW w AS (PARTITION BY batch, machine_id ORDER BY timestamp_sta range between unbounded preceding and unbounded following)
ORDER BY timestamp_sta, batch, machine_id;