【问题标题】:How can I sum the earliest and the most record in a group?如何汇总组中最早和最多的记录?
【发布时间】:2016-12-21 11:04:15
【问题描述】:

我有一张桌子,上面有 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

【问题讨论】:

  • 亲爱的,添加数据集和所需的结果集。你已经写了 350 个问题,请写得更好;)
  • 我认为 a = 10 的期望结果?
  • @Mr.Bhosale 最早也不是最不重要

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


【解决方案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;

【讨论】:

    【解决方案2】:

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

    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
    

    【讨论】:

      【解决方案3】:

      如果您要在聚合之前使用窗口函数,请使用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;
      

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

      【讨论】:

        【解决方案4】:
        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”)。

        【讨论】:

          【解决方案5】:

          检查一下。

                  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 上运行良好。

          输出:

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2015-12-10
            • 2016-07-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2022-01-20
            相关资源
            最近更新 更多