我有一个表格,其中包含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 |
+-----+------------+------------+
你看到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 |
+-----+------------+------------+
在PostgreSQL中有没有办法做到这一点?
如果我将结果作为查询结果(不一定是更新的表)
,则无关紧要答案 0 :(得分:8)
只针对返回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;
这不会改变您的表格,它只会根据需要生成结果。
请注意,生成的id列将不包含与表中的ID列相同的值,因为它只是结果集中的计数器。
您也可以将row_number()
函数替换为extract(doy from ad.date_col)
答案 1 :(得分:4)
填补空白。这不会重新排序ID:
insert into t (rainfall, "date") values
select null, "date"
from (
select d::date as "date"
from (
t
right join
generate_series(
(select date_trunc('year', min("date")) from t)::timestamp,
(select max("date") from t),
'1 day'
) s(d) on t."date" = s.d::date
where t."date" is null
) q
) s
答案 2 :(得分:4)
date
是标准SQL中的reserved word,是PostgreSQL中数据类型的名称。 PostgreSQL允许它作为标识符,但这并不是一个好主意。我使用thedate
作为列名。
不要依赖代理ID中的缺口。这几乎总是一个坏主意。将这样的ID视为唯一编号而没有含义,即使它似乎在大多数情况下承载某些其他属性。
在这种特殊情况下,@Clodoaldo commented,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);
查询全表:
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
与@a_horse_with_no_name发布的内容类似,但简化并忽略已修剪的id
。
填写表格中第一个和最后一个日期之间的差距。如果可能存在领先/滞后缺口,则相应地进行调整。你可以像@Clodoaldo那样使用date_trunc()
- 但他的查询会遇到一些语法错误,并且不必要地进行复杂处理。
最快且最易读的方法是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)
答案 3 :(得分:1)
您必须完全重新创建表,因为索引必须更改。
更好的方法是使用您喜欢的dbi语言,创建一个忽略ID的循环,并将值放入带有新序列化ID的新表中。
for day in (whole needed calendar)
value = select rainfall from oldbrokentable where date = day
insert into newcleanedtable date=day, rainfall=value, id=serialized
(这不是真正的代码!只是概念性地适应您喜欢的脚本语言)