Postgres中的ISO-8601:如何在类型日期中仅插入年份? (不完整的日期时间值)

时间:2014-02-06 10:19:52

标签: database postgresql date types iso8601

Postgres数据库claims it supports ISO-8601 standard。在ISO-8601中,日期格式“yyyy”,即仅由年份组成,是可以接受的。但我找不到一种方法只在“日期”类型的Postgres数据库字段中添加一年。如果我做错了或者Postgres中缺少这个功能,我知道吗?

我见过其他帖子建议将日期设置为“yyyy-01-01”,但这不是我想要和需要的(因为它标志着一年中某个月的特定日期)。

方案

方案如下。我们正在收集有关人员的信息。对于许多人,我们确实有确切的日期但有些人没有日期或只有年,或年和月,但没有一天。我们必须能够找到在某一年之前或之后一年之后出生的人。如果您有完整的约会,这很容易。我希望Postgres中会有一些功能可以处理不完整日期的情况。

1 个答案:

答案 0 :(得分:3)

获取date数据类型的年份:

select extract(year from '2014-01-01'::date) as the_year;
 the_year 
----------
     2014

如果您只需要年份,则使用带检查约束的smallint

create table t (
    the_year smallint check(
        the_year between 0 and extract(year from current_date)
    )
);

insert into t (the_year) values (2030);
ERROR:  new row for relation "t" violates check constraint "t_the_year_check"
DETAIL:  Failing row contains (2030).

insert into t (the_year) values (2014);
INSERT 0 1

但是如果你要存储整个日期,那么分成3列是没有意义的。

请注意,列的语义取决于应用程序。如果列属于date类型,但应用程序仅考虑年份,则该列表示年份。

检查Date/Time Functions and Operators


注释中 @a_horse 指向的部分日期问题的一个解决方案是创建一个指示该日期精度的列

create table t (
    the_date date,
    the_date_precision varchar(5)
);

insert into t (the_date, the_date_precision) values
(current_date, 'year'),
(current_date, 'month'),
(current_date, 'day')
;

select
    case the_date_precision
        when 'year' then to_char(the_date, 'YYYY')
        when 'month' then to_char(the_date, 'YYYY-MM')
        else to_char(the_date, 'YYYY-MM-DD')
    end as the_date
from t
;
  the_date  
------------
 2014
 2014-02
 2014-02-06

以上是KISS的方法,但我认为下一个实现更优雅

create table t (
    the_date date,
    the_date_precision smallint
);

insert into t (the_date, the_date_precision) values
(current_date, 1),
(current_date, 2),
(current_date, 3)
;

select
    array_to_string(
        (
            string_to_array(to_char(the_date, 'YYYY-MM-DD'), '-')
        )[1:the_date_precision]
        , '-'
    ) as the_date
from t
;
  the_date  
------------
 2014
 2014-02
 2014-02-06

可以将选择表达式转换为更容易重现的函数。或者只是view

create view view_t as 
select *,
    array_to_string(
        (
            string_to_array(to_char(the_date, 'YYYY-MM-DD'), '-')
        )[1:the_date_precision]
        , '-'
    ) as the_date_output
from t
;
select * from view_t;
  the_date  | the_date_precision | the_date_output 
------------+--------------------+-----------------
 2014-02-06 |                  1 | 2014
 2014-02-06 |                  2 | 2014-02
 2014-02-06 |                  3 | 2014-02-06