我如何总结一组中最早和最多的记录?

How can I sum the earliest and the most record in a group?

我有一个 table 和 uiddatevalue

我想按 uid 分组,得到最早找到的 value 和最近找到的 value 之间的差异。我如何在 ActiveRecord 或 SQL 中执行此操作?

示例数据:

UID   DATE        VALUE
------------------------------
a    | 2016-10-01 | 5
a    | 2016-8-01 | 10
a    | 2016-12-01 | 15
b    | 2016-10-01 | 5
b    | 2016-8-01 | 10
c    | 2016-12-01 | 15

想要的结果

UID   DELTA (absolute value)     
------------------------------
a    | 5
b    | 5
c    | 15

我对 activerecord 没有经验,但在普通的 SQL 中,您可以使用 row_number window 函数来查找第一条和最后一条记录。例如:

WITH first_and_last AS (
    SELECT uid, 
           value,
           ROW_NUMBER() OVER (PARTITION BY uid ORDER BY date ASC) as r_asc
           ROW_NUMBER() OVER (PARTITION BY uid ORDER BY date DESC) as r_desc
    FROM   mytable)
SELECT a.uid, a.value - b.value
FROM   first_and_last a
JOIN   first_and_last b ON a.uid = b.uid AND a.r_desc = 1 AND b.r_asc = 1
select uid, abs(max(latest) - max(first)) diff
from
(select uid,
  case when (row_number() over 
           (partition by uid order by date asc)) = 1 
           then value end first,
  case when (row_number() over 
           (partition by uid order by date desc)) = 1 
           then value end latest
from table
) t
group by uid;

如果要在聚合前使用 window 函数,则使用 first_value() and/or last_value():

select uid, abs(max(value_first) - max(value_last)) as diff
from (select uid,
             first_value(value) over (partition by uid order by date asc) as value_first,
             first_value(value) over (partition by uid order by date desc) as value_last
      from table
     ) t
group by uid;

如果您想使用数组聚合函数,您也可以完全不使用子查询来执行此操作。

with
  t(i,d,v) as (
    values
      ('a'::text, '2016-10-01'::date, 5::int),
      ('a', '2016-08-01', 10),
      ('a', '2016-12-01', 15),
      ('b', '2016-10-01', 5),
      ('b', '2016-08-01', 10),
      ('c', '2016-12-01', 15)),
  e as (
    select distinct on (i) * from t order by i, d),
  l as (
    select distinct on (i) * from t order by i, d desc)
select
  e.i,
  abs(e.v - case when e.d=l.d then 0 else l.v end) as diff
from
  e join l using(i);

最终查询中的case需要处理像cuid这样的情况,其中行集中只有一行(当然它不处理有多个的情况具有相同日期的行,因此您可以使用 'id'(如果存在)。

检查这个。

        select distinct a.UID,
        -- ,a."VALUE",b."VALUE",
        abs(coalesce (a."VALUE",0)-coalesce(b."VALUE",0)) 
        AS "DELTA (absolute value)"
        from
        (select * from 
        (select UID,"VALUE",ROW_NUMBER() over(PARTITION by uid order by rnk desc ) as rnk from 
        (
        select UID,"VALUE", date,ROW_NUMBER() over(PARTITION by uid order by  (select 1 ) )as rnk
        from  edata
        )a  )a where rnk='1' )a
        left join 
        ( select * FROM 
        (select UID,"VALUE",ROW_NUMBER() over(PARTITION by uid order by rnk desc ) as rnk from 
        (
        select UID,"VALUE", date,ROW_NUMBER() over(PARTITION by uid order by  (select 1 ) )as rnk
        from  edata
        )
        b )b  where    b.rnk=2 )B
        on a.uid=b.uid ORDER BY UID

也可以在此处尝试 postgresql Demo

以上代码在 SQL 服务器和 postgresql 上运行良好。

Output :