PostgreSQL中的自定义聚合函数

时间:2014-02-27 08:40:45

标签: sql database postgresql aggregate-functions

是否有可能在PostgreSQL中编写一个聚合函数,通过从当前(列中的第一个值)中减去初始值(列中的最后一个值)来计算增量值? 它适用于像这样的结构

rankings (userId, rank, timestamp)

可以像

一样使用
SELECT userId, custum_agg(rank) OVER w 
FROM rankings
WINDOWS w AS (PARTITION BY userId ORDER BY timstamp desc)

为userId返回最新条目的排名(按时间戳) - 最旧条目的排名(按时间戳记)

谢谢!

2 个答案:

答案 0 :(得分:1)

你可以在Postgres中使用JOIN和DISTINCT ON来完成。 GRP查询会为您提供每个rank的最新userID值,因此只需将rankings加入user_id并减去值。

SELECT rankings.userId, 
       rankings.rank-GRP.rank as delta,
       rankings.timestamp
FROM rankings
JOIN
(
    SELECT DISTINCT ON (userId)  userId, rank, timestamp
    FROM rankings
    ORDER BY userId, timestamp DESC
) as GRP ON rankings.userId=GRP.userId

SQLFiddle demo

答案 1 :(得分:1)

  

最新条目的排名(按时间戳) - 最旧条目的排名(按时间戳记)

有许多方法可以通过现有功能实现这一目标。 您可以使用现有的window functions first_value() and last_value(),结合DISTINCTDISTINCT ON来获取它,而无需加入和子查询:

SELECT DISTINCT ON (userid)
       userid
     , last_value(rank) OVER w  
     - first_value(rank) OVER w AS rank_delta
FROM   rankings
WINDOW w AS (PARTITION BY userid ORDER BY ts
             ROWS BETWEEN UNBOUNDED PRECEDING
             AND  UNBOUNDED FOLLOWING);

请注意自定义frames for the window functions

或者您可以在子查询和JOIN中使用基本聚合函数:

SELECT userid, r2.rank - r1.rank AS rank_delta
FROM  (
  SELECT userid
       , min(ts) AS first_ts
       , max(ts) AS last_ts
   FROM  rankings
   GROUP BY 1
   ) sub
JOIN   rankings r1 USING (userid)
JOIN   rankings r2 USING (userid)
WHERE  r1.ts = first_ts
AND    r2.ts = last_ts;

假设唯一(userid, rank),或者您的要求不明确。

SQL Fiddle demo.

Shichinin no samurai

... a.k.a. "7 Samurai"
评论中的每个请求,仅针对每个用户ID的最后七行(或者可以找到的数量,如果有更少):

再次,许多可能的方式之一。但我相信这是最短的之一:

SELECT DISTINCT ON (userid)
       userid
     , first_value(rank) OVER w  
     - last_value(rank)  OVER w AS rank_delta
FROM   rankings
WINDOW w AS (PARTITION BY userid ORDER BY ts DESC
             ROWS BETWEEN CURRENT ROW AND 7 FOLLOWING)
ORDER  BY userid, ts DESC;

请注意反向排序顺序。第一行是“最新”条目。我跨越(最多)7行的帧并仅选择DISTINCT ON的最新条目的结果。

SQL Fiddle demo.