Varchar到时间戳PostgreSQL

时间:2017-05-03 09:40:05

标签: sql database postgresql

我想要做的是将我的日期列类型从varchar更改为时区,没有时区,并迁移我的所有数据。这就是我在做的事情:

ALTER TABLE mytable ALTER COLUMN "datecol"
    TYPE timestamp without time zone USING(to_timestamp("datecol", 'YYYY-MM-DD')::timestamp without time zone);

如果datecol中的数据采用日期格式,则此方法可以正常工作。但是,如果我有一些无效的数据,如随机字符串(例如“abc”),我如何验证并检查日期格式是否良好?我想为这些无效字段设置默认值。

编辑:谢谢Ludvig,我解决了我的问题:

create or replace function is_date(s varchar) returns boolean as $$
begin
perform s::date;
return true;
exception when others then
return false;
end;
$$ language plpgsql;

ALTER TABLE mytable ALTER COLUMN "datecol"
TYPE timestamp without time zone USING(
CASE WHEN is_date("datecol") = true
THEN to_timestamp("datecol", 'YYYY-MM-DD')::timestamp without time zone
ELSE '1970-01-01 00:00:00.000'
END
);

2 个答案:

答案 0 :(得分:0)

您无法使用try/catch逻辑更改列的类型,因此您必须重新编写所有可能的格式,或者您可以:

  1. 添加专栏" ts"时间戳数据类型
  2. 添加列" exc"布尔
  3. do $$ 
      declare _r record; 
    begin 
      for _r in (select * from mytable) loop 
        update mytable set "ts" = to_timestamp("datecol", 'YYYY-MM-DD') 
        where ...PK..=_r.PK; 
      when others 
        then update mytable set "exc" = true; 
     end loop; end; $$;
    
  4. drop datecol,rename" ts"到" datecol"
  5. 处理" exc"
  6. 的价值观

    大减号会改变mytable中列的顺序。你可以在create table tt as select NEEDED order from mytable; drop table mytable;alter table tt rename to mytable之后做出不好的道歉,但是当然你也必须重建所有的引用和依赖。或者甚至更奇特的方式 - 您可以开始按需要的顺序添加列,删除重命名,直到您获得旧的设置...

答案 1 :(得分:0)

我没有测试有效日期,而是创建一个尝试使用不同格式进行投射的函数,并返回默认日期,以防它们都不起作用:

create or replace function convert_date(s varchar) 
   returns timestamp 
as 
$$
begin
  -- test standard ISO format
  begin
    return to_timestamp(s, 'yyyy-mm-dd');
  exception when others then
      -- ignore
  end;

  begin
    return to_timestamp(s, 'yyyy.mm.dd');
  exception when others then
    -- ignore
  end;

  begin
    return to_timestamp(s, 'yyyy/mm/dd');
  exception when others then
    -- ignore
  end;

  begin
    return to_timestamp(s, 'yyyy-mm');
  exception when others then
    -- ignore
  end;


  begin
    return to_timestamp(s, 'yyyy');
  exception when others then
    -- ignore
  end;

  return timestamp '1970-01-01 00:00:00';
end
$$ language plpgsql;

然后使用:

ALTER TABLE mytable 
    ALTER COLUMN "datecol" TYPE timestamp without time zone 
    USING (convert_date(datecol));

这不会非常有效,但对于一次性工作,它应该有效