ISO-8601 in Postgres: How to insert only year in type date? (incomplete date-time values)

旧巷老猫 提交于 2019-12-04 05:05:36

问题


The Postgres database claims it supports the ISO-8601 standard. In ISO-8601 a date format "yyyy", i.e. consisting of only the year, is fine and acceptable. But I can't find a way to add only a year to a Postgres database field of the type "date". Any idea if I'm doing something wrong or is this feature missing in Postgres?

I've seen other posts advising to set the date to "yyyy-01-01" but that is not what I want and need (since it marks a specific day of a month of a year).

Scenario

The scenario is the following. We are collecting information on people. For many we do have exact dates. But some have no dates or only years, or year and month but no day. We do have to be able to find people born before some year, or after some other year. This is easy if you have a full date. I hoped there would be some feature implemented in Postgres that would handle cases of incomplete dates.


回答1:


To get the year of a date data type:

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

If you only need the year then use a smallint with a check constraint

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

But if you will store the whole date then it makes no sense to separate into 3 columns.

Note that the semantics of the column are up to the application. If a column is of the date type but the application only considers the year then that column means the year.

Check the Date/Time Functions and Operators


One solution to the partial date problem pointed by @a_horse in the comments is to create a column indicating the precision of that date

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

The above is the KISS aproach but I think the next implementation is more elegant

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

That select expression could be turned into a function to be easier to reproduce. Or just a 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


来源:https://stackoverflow.com/questions/21599997/iso-8601-in-postgres-how-to-insert-only-year-in-type-date-incomplete-date-tim

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!