f.a*_*uri 2 postgresql datetime
我有一个表包含2002年每天的数据,但它有一些缺少的日期.即,2002年的354个记录(而不是365个).对于我的计算,我需要在表中包含Null值的缺失数据
+-----+------------+------------+
| ID | rainfall | date |
+-----+------------+------------+
| 100 | 110.2 | 2002-05-06 |
| 101 | 56.6 | 2002-05-07 |
| 102 | 65.6 | 2002-05-09 |
| 103 | 75.9 | 2002-05-10 |
+-----+------------+------------+
Run Code Online (Sandbox Code Playgroud)
你看,2002-05-08失踪了.我希望我的决赛桌像:
+-----+------------+------------+
| ID | rainfall | date |
+-----+------------+------------+
| 100 | 110.2 | 2002-05-06 |
| 101 | 56.6 | 2002-05-07 |
| 102 | | 2002-05-08 |
| 103 | 65.6 | 2002-05-09 |
| 104 | 75.9 | 2002-05-10 |
+-----+------------+------------+
Run Code Online (Sandbox Code Playgroud)
有没有办法在PostgreSQL中做到这一点?
如果我将结果作为查询结果(不一定是更新的表)并不重要
date
是标准 SQL 中的保留字,也是 PostgreSQL 中数据类型的名称。PostgreSQL 允许它作为标识符,但这并不是一个好主意。我thedate
改为用作列名。
不要依赖代理 ID 中没有空白。这几乎总是一个坏主意。将这样的 ID 视为没有意义的唯一编号,即使它在大多数情况下似乎带有某些其他属性。
在这种特殊情况下,正如@Clodoaldo 评论的那样,它thedate
似乎是一个完美的主键,而该列id
只是杂乱无章-我将其删除:
CREATE TEMP TABLE tbl (thedate date PRIMARY KEY, rainfall numeric);
INSERT INTO tbl(thedate, rainfall) VALUES
('2002-05-06', 110.2)
, ('2002-05-07', 56.6)
, ('2002-05-09', 65.6)
, ('2002-05-10', 75.9);
Run Code Online (Sandbox Code Playgroud)
按查询的完整表:
SELECT x.thedate, t.rainfall -- rainfall automatically NULL for missing rows
FROM (
SELECT generate_series(min(thedate), max(thedate), '1d')::date AS thedate
FROM tbl
) x
LEFT JOIN tbl t USING (thedate)
ORDER BY x.thedate
Run Code Online (Sandbox Code Playgroud)
类似于@a_horse_with_no_name发布的内容,但简化并忽略了修剪后的id
.
填补表格中第一个和最后一个日期之间的空白。如果可能存在领先/滞后差距,请相应地延长。您可以date_trunc()
像@Clodoaldo演示的那样使用- 但他的查询存在语法错误并且可以更简单。
最快和最易读的方法是NOT EXISTS
反半连接。
INSERT INTO tbl (thedate, rainfall)
SELECT x.thedate, NULL
FROM (
SELECT generate_series(min(thedate), max(thedate), '1d')::date AS thedate
FROM tbl
) x
WHERE NOT EXISTS (SELECT 1 FROM tbl t WHERE t.thedate = x.thedate)
Run Code Online (Sandbox Code Playgroud)
只针对返回2002年所有日期的查询执行外连接:
with all_dates as (
select date '2002-01-01' + i as date_col
from generate_series(0, extract(doy from date '2002-12-31')::int - 1) as i
)
select row_number() over (order by ad.date_col) as id,
t.rainfall,
ad.date_col as date
from all_dates ad
left join your_table t on ad.date_col = t.date
order by ad.date_col;
Run Code Online (Sandbox Code Playgroud)
这不会改变你的表,它只会产生所需的结果.
请注意,生成的id列将不包含与表中的ID列相同的值,因为它只是结果集中的计数器.
您也可以用.替换该row_number()
功能extract(doy from ad.date_col)