Postgresql日期格式

时间:2012-01-28 06:27:53

标签: postgresql date formatting postgresql-8.4

我有一个数据集(格式为.tsv),其中一列是出生日期。但是,数据是旧的,并非所有日期都是YYYY-MM-DD格式。有些条目只有他们的出生年份(出生月份和出生日期),并且格式YYYY-##-##(字面上##已经插入数据中,只有年份已知)。我希望将此数据集加载到我的 postgres 数据库中,并使用出生日期列,数据类型为date而不是string,以便我可以在日期做比较 一小部分样本如下所示。 (不显示不相关的数据列)

1924-##-##
1965-09-04
1944-11-05
1951-##-##
-388-##-##
1893-01-26
1037-##-##

直接批量加载数据集显然会出错

ERROR:  invalid input syntax for type date: "1924-##-##"
LINE 1: insert into d values ('1924-##-##');
                              ^

数据集非常大,大约有6亿个条目。目前我正在考虑运行一个脚本,用##替换这些01,然后将修改后的数据插入数据库。但我不喜欢这个想法 -

  1. 这很费时间。
  2. 这是耗费磁盘空间的(因为我希望保留原始的“umtampered”数据)
  3. 此外,我的数据库中并非所有数据都是正版数据。
  4. 有什么方法可以让postgres以某种方式只是按照日期,只是忽略`##'(只保留缺少月份和日期的年份)? 或者可以有更好的解决方案解决这个问题吗?

3 个答案:

答案 0 :(得分:1)

您可以在表格中创建两列,一列用于最初输入的值(varchar的类型),另一列用于计算(类型日期)。

CREATE TABLE your_table
(
 id INT,
 -- OTHER DETAILS
 dob_entered    VARCHAR,
 dob_parsed DATE
);

然后,您可以使用Insert触发器自动从varchar填充日期字段,并使用更新触发器来处理任何更改。

CREATE OR REPLACE FUNCTION evaluate_dob_date() RETURNS TRIGGER AS
$$
BEGIN
    NEW.dob_parsed = CAST(REPLACE(NEW.dob_entered,'##','01') AS DATE);
    RETURN new;
END;
$$
LANGUAGE plpgsql;

CREATE TRIGGER parse_dob 
BEFORE INSERT OR UPDATE ON your_table
FOR EACH ROW
EXECUTE PROCEDURE evaluate_dob_date();

这意味着您存储原始输入的数据以进行验证,同时数据库中的日期字段仍然适合排序和比较等。另外,通过扩展evaluate_dob_date()功能,您可以匹配不同的你找到它们的情况,同时仍然可以拒绝真正无效的记录。

Postgresql triggers

答案 1 :(得分:0)

这里有两个选择

  1. 从数据库中获取数据后,在服务器端脚本中替换所有出现的#,然后比较日期。 (您也可以在表中动态替换数据,而无需使用查询中的if条件修改现有数据)
  2. 忽略包含#的日期。这样您就可以仅比较有效日期。

答案 2 :(得分:0)

如果您需要保留#字符,我看到的唯一机会就是将其导入varchar列。

如果您绝对需要将信息作为日期,那么您可能会获得执行转换的视图,并且只会选择列中没有#的行。

这样的东西
SELECT to_date(dob,'YYYY-MM-DD') as dob_date
FROM your_table
WHERE substr(dob,6,2) <> '##';

如果您定期执行此操作,您可能需要考虑该表达式的索引以加快选择:

CREATE INDEX dob_check ON your_table( substr(dob,6,2) );

请注意,select中的表达式必须与完全索引中的表达式匹配才能被查询计算器使用。

如果您想在检索期间将数据“转换”为有效日期,您可以执行以下操作:

SELECT case 
         case when substr(dob,6,2) = '##' then to_date(substr(dob,1,5)||'01-01', 'YYYY-MM-DD')
         else to_date(dob,'YYYY-MM-DD')
       end as dob_date
FROM your_table;