仅在timestamptz中提供日期时执行默认时间

时间:2012-06-12 17:29:41

标签: postgresql default-value

假设我有桌子:

postgres=# create table foo (datetimes timestamptz);
CREATE TABLE
postgres=# \d+ foo 
                            Table "public.foo"
  Column   |           Type           | Modifiers | Storage | Description 
-----------+--------------------------+-----------+---------+-------------
 datetimes | timestamp with time zone |           | plain   | 
Has OIDs: no

所以让我们插入一些值......

postgres=# insert into foo values 
    ('2012-12-12'), --This is the value I want to catch for.
    (null), 
    ('2012-12-12 12:12:12'), 
    ('2012-12-12 12:12');
INSERT 0 4

这就是我们所拥有的:

postgres=# select * from foo ;
       datetimes        
------------------------
 2012-12-12 00:00:00+00

 2012-12-12 12:12:12+00
 2012-12-12 12:12:00+00
(4 rows)

理想情况下,我想在没有提供输入时设置默认时间戳值,而不是2012-12-12 00:00:00的实际时间,我会喜欢设置默认值15:45:10

意思是,我的结果应该看起来像:

postgres=# select * from foo ;
       datetimes        
------------------------
 2012-12-12 15:45:10+00    --This one gets the default time.

 2012-12-12 12:12:12+00
 2012-12-12 12:12:00+00
(4 rows)

我不确定如何在postgres 8.4中执行此操作,我在手册的datetime部分或有关列默认值的部分中找不到任何内容。

1 个答案:

答案 0 :(得分:3)

可以在BEFORE INSERT触发器中调整新行的值。这样的触发器 可以测试NEW.datetimes中是否存在非零时间分量,如果没有将其设置为所需的固定时间。

但是,在INSERT子句中将时间部分显式设置为零的情况无法使用此技术处理,因为'2012-12-12'::timestamptz等于'2012-12-12 00:00:00'::timestamptz。因此,尝试将0.0与0.00区分开来。

从技术上讲,调整值应该在从字符串到列的类型的隐式强制转换之前发生,即使是RULE(动态查询重写)也不行。

在我看来,最好的选择是重写INSERT并将函数应用于每个值,将其从字符串显式转换为时间戳。此函数将测试输入格式并在需要时添加时间部分:

  create function conv(text) returns timestamptz as $$
    select case when length($1)=10 then ($1||' 15:45:10')::timestamptz
      else $1::timestamptz end; $$
   language sql strict immutable;

insert into foo values 
    (conv('2012-12-12')),
    (conv(null)), 
    (conv('2012-12-12 12:12:12')), 
    (conv('2012-12-12 12:12'));