13

我正在尝试编写查询以将值插入timestamp with no timezone data类型字段。该值来自 CSV 文件。

我正在使用的版本是PostgreSQL 8.1.21

CSV 文件上传由客户端完成,它有一个日期列。日期有时以格式出现'28-Sep-13',有时以'28/09/2013'格式出现。

我尝试使用以下内容将字符串转换为时间戳: str_date::timestamp.

如果str_date是类似的东西,这可以正常工作,但如果传入的日期具有 format ,则在发生此错误时'28-Sep-13'它将不起作用:'28/09/2013'

ERROR: date/time field value out of range: "28/09/2013"  
HINT:  Perhaps you need a different "datestyle" setting

基本上,客户端会不断更改上传的 CSV 文件中的日期格式。
有没有办法根据实际格式将日期字符串转换为时间戳?

4

3 回答 3

17

您需要将日期样式设置为“ISO,DMY”。它默认设置为“ISO,MDY”,并会导致您的示例失败:

> show datestyle;

 DateStyle 
-----------
 ISO, MDY
(1 row)

> select '28-Sep-13'::date;
    date    
------------
 2013-09-28
(1 row)

> select '28/09/2013'::date;
ERROR:  date/time field value out of range: "28/09/2013"
LINE 1: select '28/09/2013'::date;
               ^
HINT:  Perhaps you need a different "datestyle" setting.

> set datestyle = 'ISO, DMY';
SET

> select '28-Sep-13'::date;
    date    
------------
 2013-09-28
(1 row)

> select '28/09/2013'::date;
    date    
------------
 2013-09-28
(1 row)

(在 PostgreSQL 9.1 中完成的示例,但 DateStyle 设置和相关行为是古老的,所以应该可以正常工作)

于 2011-11-15T19:47:05.520 回答
7

您可以通过以下步骤规避该问题:

  1. 创建一个与目标表结构相同的空临时表:

    CREATE TEMP TABLE tmp AS SELECT * FROM real_tbl LIMIT 0;
    
  2. 将有问题的列的类型更改为text

    ALTER TABLE tmp ALTER COLUMN str_date TYPE text;
    
  3. 将数据导入临时表。现在应该可以正常工作:

    COPY tmp FROM '/path/to/my/file.txt';
    
  4. INSERT根据列的实际内容进入目标表:

    INSERT INTO real_tbl (col1, col2, col3, date_col)
    SELECT col1, col2, col3
         , CASE WHEN str_date ~~ '%/%'
              THEN to_date(str_date, 'DD/MM/YYYY')
           WHEN str_date ~~ '%-%'
              THEN to_date(str_date, 'DD-Mon-YYYY')
            -- more cases?
           ELSE ???
           END AS date_col
    FROM   tmp;
    
    -- DROP TABLE tmp;  -- optional; dropped at end of session automatically
    
于 2011-11-15T02:20:16.753 回答
1

我同意 Erwin,但我会尝试创建可以将各种日期字符串转换为date. 在 Erwins 的回答中,您可以看到WHEN ... THEN并且可以使用它。这样的功能将更容易测试和维护。

于 2011-11-15T09:12:57.170 回答