PostgreSQL选择具有动态日期范围的计数

och*_*hii 4 postgresql postgresql-9.6

首先,我是这个论坛的新手。我希望有人能就我的问题提供帮助或建议。

给定用户 createdAt 日期和当前日期。我想在这些日期之间以 10 个线性时间间隔检索用户的 Friends 记录总和。

因此,如果 createdAt 是 30 天前,那么我想要每隔 3 天间隔的用户好友总数。

用户表

??????????????????????????????????????????????
? id ? name     ? createdAt                  ?
??????????????????????????????????????????????
? 1  ? Timothee ? 2018-03-01 13:02:20.904+00 ?
??????????????????????????????????????????????
Run Code Online (Sandbox Code Playgroud)

朋友桌

???????????????????????????????????????????????????????
? id ? userId ? friendId ? createdAt                  ?
???????????????????????????????????????????????????????
? 1  ? 1      ? 234      ? 2018-03-20 15:41:51.779+00 ?
???????????????????????????????????????????????????????
? 2  ? 1      ? 254      ? 2018-03-20 16:16:34.698+00 ?
???????????????????????????????????????????????????????
? 3  ? 1      ? 288      ? 2018-03-15 15:17:39.907+00 ?
???????????????????????????????????????????????????????
? 4  ? 1      ? 293      ? 2018-03-07 16:15:49.379+00 ?
???????????????????????????????????????????????????????
Run Code Online (Sandbox Code Playgroud)

预期产出

?????????????????????????????????????????????????????????????????????
? ? count ? startDate                  ? endDate                    ?
?????????????????????????????????????????????????????????????????????
? ? 0     ? 2018-03-01 13:02:20.904+00 ? 2018-03-03 13:02:20.904+00 ?
?????????????????????????????????????????????????????????????????????
? ? 0     ? 2018-03-03 13:02:20.904+00 ? 2018-03-05 13:02:20.904+00 ?
?????????????????????????????????????????????????????????????????????
? ? 0     ? 2018-03-05 13:02:20.904+00 ? 2018-03-07 13:02:20.904+00 ?
?????????????????????????????????????????????????????????????????????
? ? 1     ? 2018-03-07 13:02:20.904+00 ? 2018-03-09 13:02:20.904+00 ?
?????????????????????????????????????????????????????????????????????
? ? 1     ? 2018-03-09 13:02:20.904+00 ? 2018-03-11 13:02:20.904+00 ?
?????????????????????????????????????????????????????????????????????
? ? 1     ? 2018-03-11 13:02:20.904+00 ? 2018-03-13 13:02:20.904+00 ?
?????????????????????????????????????????????????????????????????????
? ? 1     ? 2018-03-13 13:02:20.904+00 ? 2018-03-15 13:02:20.904+00 ?
?????????????????????????????????????????????????????????????????????
? ? 2     ? 2018-03-15 13:02:20.904+00 ? 2018-03-17 13:02:20.904+00 ?
?????????????????????????????????????????????????????????????????????
? ? 2     ? 2018-03-17 13:02:20.904+00 ? 2018-03-19 13:02:20.904+00 ?
?????????????????????????????????????????????????????????????????????
? ? 4     ? 2018-03-19 13:02:20.904+00 ? 2018-03-21 13:02:20.904+00 ?
?????????????????????????????????????????????????????????????????????
Run Code Online (Sandbox Code Playgroud)

我可以使用以下 SQL-Server 查询获得所需的天数间隔:

@DECLARE @EndDate DATE = GETDATE();
WITH start as 
(SELECT createdAt
 FROM user where id = '123'
) 
SELECT diff/10 
FROM ( 
    SELECT DATEDIFF(days, start, @EndDate) 
) as diff
Run Code Online (Sandbox Code Playgroud)

这在 PostgreSQL 中会怎样?

我也知道我可以使用 SQL-Server 查询检索静态日期范围之间的记录数:

SELECT count(*)
FROM friends
WHERE userId = '123'
AND date BETWEEN CURDATE() - INTERVAL 3 DAY AND CURDATE()
Run Code Online (Sandbox Code Playgroud)

这在 PostgreSQL 中会怎样?

但我正在努力解决的是这两件事的结合。

如何检索两个日期之间所有日期间隔内的记录总和?

我希望这个问题是可以理解的,感谢您的任何帮助或建议。

McN*_*ets 7

Postgres 允许使用 generate_series() 函数生成一系列日期。

select generate_series(createdAt, current_date, 
       (date_part('day', current_date::timestamp - createdAt::timestamp) / 10)::int * '1 day'::interval) ddate
       , (date_part('day', current_date::timestamp - createdAt::timestamp) / 10)::int * '1 day'::interval as ddays                
from   users
where  id = 1;
Run Code Online (Sandbox Code Playgroud)

它返回:

日期 | 天
:-------------- | :-----
2018-03-01 13:02:20.904 | 2天
2018-03-03 13:02:20.904 | 2天
2018-03-05 13:02:20.904 | 2天
2018-03-07 13:02:20.904 | 2天
2018-03-09 13:02:20.904 | 2天
2018-03-11 13:02:20.904 | 2天
2018-03-13 13:02:20.904 | 2天
2018-03-15 13:02:20.904 | 2天
2018-03-17 13:02:20.904 | 2天
2018-03-19 13:02:20.904 | 2天

然后您可以使用先前的查询来计算此间隔之间的朋友数:

with x as
(
    select generate_series(createdAt, current_date, 
           (date_part('day', current_date::timestamp - createdAt::timestamp) / 10)::int * '1 day'::interval) ddate
           , (date_part('day', current_date::timestamp - createdAt::timestamp) / 10)::int * '1 day'::interval as ddays
    from   users
    where  id = 1
)
select ddate,
       (select count(*)
        from   friends
        where  createdAt >= ddate
        and    createdAt <  ddate + ddays) friends
from x;
Run Code Online (Sandbox Code Playgroud)

最后结果:

日期 | 朋友们
:-------------- | ------:
2018-03-01 13:02:20.904 | 0
2018-03-03 13:02:20.904 | 0
2018-03-05 13:02:20.904 | 0
2018-03-07 13:02:20.904 | 1
2018-03-09 13:02:20.904 | 0
2018-03-11 13:02:20.904 | 0
2018-03-13 13:02:20.904 | 0
2018-03-15 13:02:20.904 | 1
2018-03-17 13:02:20.904 | 0
2018-03-19 13:02:20.904 | 2

或者,如果您更喜欢连接而不是相关的标量子查询:

with x as
(
    select generate_series(createdAt, current_date, 
           (date_part('day', current_date::timestamp - createdAt::timestamp) / 10)::int * '1 day'::interval) ddate
           , (date_part('day', current_date::timestamp - createdAt::timestamp) / 10)::int * '1 day'::interval as ddays
    from   users
    where  id = 1
)
select ddate,
       count(friends.*) as friends
from   x
left join   friends
on     createdAt >= ddate
and    createdAt <  ddate + ddays
group by ddate
order by ddate;
Run Code Online (Sandbox Code Playgroud)

根据您的预期输出,可以进一步修改最后一个选项以返回运行总计:

with x as
(
    select generate_series(createdAt, current_date, 
           (date_part('day', current_date::timestamp - createdAt::timestamp) / 10)::int * '1 day'::interval) ddate
           , (date_part('day', current_date::timestamp - createdAt::timestamp) / 10)::int * '1 day'::interval as ddays
    from   users
    where  id = 1
)
select ddate,
       count(friends.*) as friends,
       sum(count(friends.*)) over (order by ddate) as friends_total
from   x
left join   friends
on     createdAt >= ddate
and    createdAt <  ddate + ddays
group by ddate
order by ddate;
Run Code Online (Sandbox Code Playgroud)

结果:

日期 | 朋友 | 朋友总数
:-------------- | ------: | ------------:
2018-03-01 13:02:20.904 | 0 | 0
2018-03-03 13:02:20.904 | 0 | 0
2018-03-05 13:02:20.904 | 0 | 0
2018-03-07 13:02:20.904 | 1 | 1
2018-03-09 13:02:20.904 | 0 | 1
2018-03-11 13:02:20.904 | 0 | 1
2018-03-13 13:02:20.904 | 0 | 1
2018-03-15 13:02:20.904 | 1 | 2
2018-03-17 13:02:20.904 | 0 | 2
2018-03-19 13:02:20.904 | 2 | 4

dbfiddle在这里