为 PostgreSQL 中按日期设置的唯一组添加缺失的行

时间:2021-04-10 15:23:47

标签: postgresql group-by aggregate-functions missing-data generate-series

我有一个表,其中包含 game_idcategory、表示一个月活动的日期列,表示为该月的第一天 date_month,总计 {{1} }.

在某些月份,amountgame_id 缺少类别,我需要为每个游戏的每个月内整个表格中缺少的唯一组集填充这些缺失的行。< /p>

举个例子:

date_month

在这种情况下,需要使用 0 金额创建以下缺失值,CREATE TEMPORARY TABLE activity ( game_id INT, category TEXT, date DATE, amount INT ); INSERT INTO activity (game_id, category, date, amount) VALUES (1, 'Up', '2015-12-01', 9) , (1, 'Down', '2015-12-01', 12) -- Left Missing for '2015-12-01 -- Right Missing for '2015-12-01 , (1, 'Up', '2016-01-01', 12) , (1, 'Down', '2016-01-01', 4) , (1, 'Left', '2016-01-01', 7) , (1, 'Right', '2016-01-01', 3) , (1, 'Up', '2016-02-01', 3) , (1, 'Down', '2016-02-01', 11) , (1, 'Left', '2016-02-01', 4) , (1, 'Right', '2016-02-01', 8) , (1, 'Up', '2016-03-01', 3) , (1, 'Down', '2016-03-01', 11) -- Left Missing for '2016-03-01' , (1, 'Right', '2016-03-01', 8) , (1, 'Up', '2016-04-01', 3) , (1, 'Down', '2016-04-01', 11) , (1, 'Left', '2016-04-01', 4) -- Right Missing for '2016-04-01' , (2, 'Up', '2020-12-01', 9) , (2, 'Down', '2020-12-01', 12) -- Left Missing for '2020-12-01' -- Right Missing for '2020-12-01' , (2, 'Up', '2020-01-01', 12) , (2, 'Down', '2020-01-01', 4) , (2, 'Left', '2020-01-01', 7) -- Right Missing for '2020-01-01' ; 可以具有一组不同的日期范围。

game_id

到目前为止,我的目的是在 (1, 'Left', '2015-12-01', 0) (1, 'Right', '2015-12-01', 0) (1, 'Left', '2016-03-01', 0) (1, 'Right', '2016-04-01', 0) (2, 'Left', '2020-12-01', 0) (2, 'Right', '2020-12-01', 0) (2, 'Right', '2020-01-01', 0) 中使用它回到主表。这不会产生任何行,因为不会生成超出其最小和最大日期范围的缺失组。

UNION

1 个答案:

答案 0 :(得分:1)

您必须CROSS将表的不同game_iddate组合连接到表的不同category,然后LEFT连接到表:

SELECT d.game_id, c.category, d.date, COALESCE(a.amount, 0) amount
FROM (SELECT DISTINCT game_id, date FROM activity) d
CROSS JOIN (SELECT DISTINCT category FROM activity) c
LEFT JOIN activity a 
ON a.game_id = d.game_id AND a.date = d.date AND a.category = c.category
ORDER BY d.game_id, d.date

如果要在表中插入缺失的行:

INSERT INTO activity (game_id, category, date, amount)
SELECT d.game_id, c.category, d.date, 0
FROM (SELECT DISTINCT game_id, date FROM activity) d
CROSS JOIN (SELECT DISTINCT category FROM activity) c
LEFT JOIN activity a 
ON a.game_id = d.game_id AND a.date = d.date AND a.category = c.category
WHERE a.game_id IS NULL

参见demo