如何将一组中最早和最多的记录相加?

时间:2016-12-21 11:04:16

标签: sql postgresql select activerecord ruby-on-rails-5

我有一张包含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

5 个答案:

答案 0 :(得分:3)

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;

答案 1 :(得分:2)

我没有使用activerecord,但在纯SQL中,您可以使用row_number窗口函数查找第一个和最后一个记录。 E.g:

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

答案 2 :(得分:0)

如果要在聚合之前使用窗口函数,请使用first_value()和/或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;

如果要使用数组聚合函数,也可以在没有子查询的情况下执行此操作。

答案 3 :(得分:0)

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需要处理像c uid这样的情况,其中行集中只有一行(当然它不处理具有多行的情况)相同的日期,所以你可以使用'id'(如果它存在)。

答案 4 :(得分:0)

检查这个。

        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 Server和postgresql。

  

输出:

enter image description here