Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/postgresql/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在PostgreSQL中的表中添加缺少的日期_Postgresql_Datetime - Fatal编程技术网

在PostgreSQL中的表中添加缺少的日期

在PostgreSQL中的表中添加缺少的日期,postgresql,datetime,Postgresql,Datetime,我有一个表,其中包含2002年每天的数据,但它缺少一些日期。即2002年有354项记录(而不是365项)。对于我的计算,我需要在表中包含空值的缺失数据 +-----+------------+------------+ | ID | rainfall | date | +-----+------------+------------+ | 100 | 110.2 | 2002-05-06 | | 101 | 56.6 | 2002-05-07 | | 10

我有一个表,其中包含2002年每天的数据,但它缺少一些日期。即2002年有354项记录(而不是365项)。对于我的计算,我需要在表中包含空值的缺失数据

+-----+------------+------------+
| 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中有这样做的方法吗


如果我的结果只是一个查询结果(不一定是一个更新的表),这并不重要。

您必须完全重新创建表,因为索引必须更改

更好的方法是使用您喜欢的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

(这不是真正的代码!只是概念性的,以适应您喜欢的脚本语言)

来填补空白。这不会对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

只需对返回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列相同的值,因为它只是结果集中的一个计数器

您还可以将
行号()
函数替换为
提取(doy from ad.date\u col)

date
是标准SQL中的数据类型,也是PostgreSQL中的数据类型名称。PostgreSQL允许它作为标识符,但这并不是一个好主意。我使用日期作为列名

不要依赖于代理ID中没有空白。这几乎总是一个坏主意。将这样一个ID视为没有意义的唯一数字,即使它在大多数情况下似乎带有某些其他属性

在这种情况下,
date
似乎是一个完美的主键,
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
与发布的内容类似,但简化并忽略删减的
id

填补表中第一个和最后一个日期之间的空白。如果可能存在超前/滞后间隙,则相应延长。您可以像演示的那样使用
date\u trunc()

插入缺少的行 最快和最可读的方法是
不存在
反半联接

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)

身份证是序列号吗?当插入日期时,是否需要全部向上移动?是的,我需要更改ID,就像我放在这里的示例表一样。在整整一年结束时,最后一个ID将是365。我确实读了你的其他帖子(回答了一个),我认为你做错了。您不应该依赖ID进行排序或分组。这是一个重要的日期。如果你想填补空白,这是可以的,它可以使查询更容易,但严格来说不是必要的。在“日期”列上创建一个唯一的索引,以确保它们不会重复。我在回答如何填补空白。是的,你是对的。我必须根据日期而不是ID进行分组。但问题是我无法根据日期进行分组。我试试看。谢谢,如果12月31日不在表中怎么办?在这种情况下,generate_series()将无法创建足够的值。@a_horse_带有_no_name Yes,这是设计的。我认为他不想要或不应该想要未来的日期。不,他想要结果中的365行。@a_nou horse_和_No_name阅读了我关于我为什么认为这是错误的问题的评论。他还可以将所有id重新编号为无意义的值(
UPDATE table SET id=-id
),然后正确地重新编号(
UPDATE table SET id=q.val FROM)(选择date,row_number()OVER(ORDER BY date)作为val FROM table)q其中q.date=table.date
)。也就是说,我同意@Clodoaldo的说法,这是错误的……而且效率极低。如果您想编写一个新的干净表,您可以使用一个SQL命令,在其中使用
row_number()生成新的
id
或从没有窗口函数的旧版本中的序列。但整个想法都不好。依靠代理键中没有间隙不是一个好主意。我为我的表运行了此操作,遇到了以下错误:错误:对表“ad”的from子句项的引用无效第13行:left join rwanda1 t on ad.date\u col=t.date提示:表“ad”有一个条目,但不能从查询的这一部分引用它。