我如何总结一组中最早和最多的记录?
How can I sum the earliest and the most record in a group?
我有一个 table 和 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
我对 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
需要处理像c
uid
这样的情况,其中行集中只有一行(当然它不处理有多个的情况具有相同日期的行,因此您可以使用 '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 :
我有一个 table 和 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
我对 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
需要处理像c
uid
这样的情况,其中行集中只有一行(当然它不处理有多个的情况具有相同日期的行,因此您可以使用 '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 :