按比例计算条纹

问题描述 投票:0回答:1

所以我需要计算用户的连续记录(他创建条目的连续天数)。目前,我进行了一个对条目进行分组的查询,它给了我最后一组条纹。这是架构的一部分(postgres):

CREATE TABLE "diaries" (
"id" SERIAL NOT NULL,
"text" VARCHAR(4000),
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"user_profile_id" INTEGER NOT NULL,

CONSTRAINT "diaries_pkey" PRIMARY KEY ("id"));

这是查询

WITH daily_entries AS (
    SELECT
        user_profile_id,
        created_at::date AS entry_date
    FROM
        diaries
    WHERE
        user_profile_id = 1
        AND created_at::date <= CURRENT_DATE
    GROUP BY
        user_profile_id, created_at::date
),
streaks AS (
    SELECT
        user_profile_id,
        entry_date,
        entry_date - INTERVAL '1 day' * ROW_NUMBER() OVER (PARTITION BY user_profile_id ORDER BY entry_date) AS streak_group
    FROM
        daily_entries
),
streaks_summary AS (
    SELECT
        user_profile_id,
        MIN(entry_date) AS streak_start,
        MAX(entry_date) AS streak_end,
        COUNT(*) AS streak_length
    FROM
        streaks
    GROUP BY
        user_profile_id, streak_group
)
SELECT
    streak_length
FROM
    streaks_summary
WHERE
    streak_end = CURRENT_DATE
    AND (user_profile_id = 1);

我正在寻找一种优化扩展的方法。我正在考虑在创建时计算的每个条目中添加一个字段“条纹”,这样就不需要重新计算整个表的条纹,但我不确定这个解决方案。还有其他现有的方法吗?

sql postgresql gaps-and-islands
1个回答
0
投票

您可以考虑间隙和孤岛类型任务的常用解决方案。
它是否会比你提出的更好是一个有趣的问题。

示例

select  user_profile_id,min(created_at) start_from,max(created_at) end_to,count(*) cnt
  ,count(distinct created_at::date)qd
from(
  select *
    ,sum(new_streak)over(PARTITION BY user_profile_id ORDER BY created_at) grn
  from(
    select *
    ,case when  
      lag(created_at,1,created_at)OVER(PARTITION BY user_profile_id ORDER BY created_at)::date
       >= created_at::date - INTERVAL '1 day'
       then 0 
     else 1
     end new_streak
    from diaries
    where  (user_profile_id = 1)
    AND created_at::date <= CURRENT_DATE
  )t
)
group by user_profile_id,grn
having max(created_at)::date=current_date

小提琴

一些优化 - 获取最后一组行

select user_profile_id,min(created_at) start_from,max(created_at) end_to,count(*) cnt
  ,count(distinct created_at::date)qd
from(
  select *
    ,sum(new_streak)over(PARTITION BY user_profile_id ORDER BY created_at desc) grn
  from(
    select *
    ,case when  
      lag(created_at,1,created_at)
               OVER(PARTITION BY user_profile_id ORDER BY created_at desc)::date
       <= created_at::date + INTERVAL '1 day'
       then 0 
     else 1
     end new_streak
    from diaries
    where  (user_profile_id = 1)
    AND created_at::date <= CURRENT_DATE
  )t
)
where grn=0
group by user_profile_id
用户个人资料_id 开始于 结束 cnt qd
1 2024-06-16 19:00:00 2024-06-18 21:00:00 6 3

我们按照

desc
的顺序分组,并选择第一组。

id 文字 创建于 用户个人资料_id 新条纹 grn
15 文字1-2 2024-06-18 21:00:00 1 0 0
14 文字1-2 2024-06-17 18:59:00 1 0 0
13 文字1-2 2024-06-16 22:00:00 1 0 0
12 文字1-2 2024-06-16 21:00:00 1 0 0
11 文字1-2 2024-06-16 20:00:00 1 0 0
10 文字1-2 2024-06-16 19:00:00 1 0 0
9 文字1-2 2024-06-09 20:00:00 1 1 1
8 文字1-2 2024-06-08 19:00:00 1 0 1
7 文字1-2 2024-06-06 19:00:00 1 1 2
6 文字1-2 2024-06-05 19:00:00 1 0 2
5 文字1-2 2024-06-04 19:00:00 1 0 2
4 文字1-2 2024-06-03 19:00:00 1 0 2
3 文字1-2 2024-06-02 19:00:00 1 0 2
2 文字1-2 2024-06-02 19:00:00 1 0 2
1 文本1-1 2024-06-01 19:00:00 1 0 2
© www.soinside.com 2019 - 2024. All rights reserved.