我有一张这样的桌子:
-----------------
id | date
-----------------
1 | 2023-10-07
2 | 2023-10-08
3 | 2023-10-14
并且我想获取截至当前记录的记录计数,其中日期小于当前记录的星期日。所以我希望输出看起来像这样:
---------------------
week_number | count
---------------------
2 | 2
3 | 3
我尝试了不同的方法,但结果是一周内的条目计数器。就好像他不查看当前记录之前的所有记录,而只查看同一周内的记录。
WITH weekly AS (
SELECT
get_week_number(date::DATE) AS week_number,
COUNT(*) AS count
FROM
inventory
WHERE
date <= date_trunc('week', date)::date + INTERVAL '6 days'
GROUP BY
week_number
)
SELECT
week_number, count
FROM
inventory
JOIN weekly ON get_week_number(date::DATE) = weekly.week_number
WHERE
date <= date_trunc('week', date)::date + INTERVAL '6 days'
GROUP BY
week_number, count
ORDER BY
week_number;
您可能正在寻找窗口函数。 db<>fiddle 的演示
select id,
date,
extract(week from date) AS week_number,
count(*)over(order by date) AS count
from inventory order by id;
id | 日期 | 周数 | 数 |
---|---|---|---|
1 | 2023-10-07 | 40 | 1 |
2 | 2023-10-08 | 40 | 2 |
3 | 2023-10-14 | 41 | 3 |
select week_number,
sum(count)over(order by week_number)
from( select extract(week from date::DATE) AS week_number,
count(*) AS count
from inventory
group by week_number) AS subquery;
周数 | 总和 |
---|---|
40 | 2 |
41 | 3 |
默认窗口frame子句是
RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
,这意味着count()over()
将按照您想要的方式获取当前记录的记录计数。
这个计算
日期小于当前记录周日的记录计数到当前记录
SELECT *
, extract(week FROM date + 1) AS week_nr -- fix off-by-1
, count(*) OVER (ORDER BY date_bin('7 days', date, timestamp '2023-1-1')
RANGE BETWEEN UNBOUNDED PRECEDING AND '1 day' PRECEDING) AS count_til_last_week
FROM inventory;
我假设“当前记录的星期日”您的意思是从星期日开始的几周。 ISO 周从周一开始。 date_trunc()
相应地截断周。使用
date_bin()
“截断”到星期日。参见:在提取周数之前向日期添加一天,以修复相同的相差 1 的错误。 (年底前后可能会出现极端情况问题。)
要获取具有
“日期小于当前记录的星期日” 的行数,您必须在“上周”停止计数。 RANGE BETWEEN UNBOUNDED PRECEDING AND '1 day' PRECEDING
在将每个日期减少到一周中的星期日后实现了这一目标。详情请参阅
:
SELECT extract(year FROM sun) AS year
, extract(week FROM sun + interval '1 day') AS week_number
, sum(row_count) OVER (ORDER BY sun
ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING) AS count_til_last_week
FROM (
SELECT date_bin('7 days', date, timestamp '2023-1-1') AS sun
, count(*) AS row_count
FROM inventory
GROUP BY 1
) sub;
请注意,没有年份的周数会很快导致混乱或错误的聚合。因此,我根据完整日期进行计数并另外显示年份。 (那里没有减 1。)小提琴