我有一张包含uid
,date
和value
的表格。
我想通过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
答案 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。
输出: