PostgreSQL:与datetime之间

Den*_*SkS 13 sql postgresql datetime postgresql-8.4

我使用PostgreSQL 8.4.11并发现奇怪的错误.当我查询时:

SELECT "documents_document"."given_on" 
FROM "documents_document" 
WHERE (EXTRACT('month' FROM "documents_document"."given_on") = 1
       AND "documents_document"."given_on" 
       BETWEEN '1-01-01 00:00:00' and '1-12-31 23:59:59.999999') 
ORDER BY "documents_document"."created_on" DESC
Run Code Online (Sandbox Code Playgroud)

我得到了结果:

  given_on  
------------
 2002-01-16
 2011-01-25
 2012-01-12
 2012-01-12
 2012-01-12
 2012-01-20
 2012-01-19
 2012-01-13
 2012-01-31
 2012-01-16
 2012-01-31
 2012-01-12
 ...
Run Code Online (Sandbox Code Playgroud)

为什么?

我希望日期在1-01-01 ... 1-12-31.

Erw*_*ter 24

你期待1-01-01 ... 1-12-31......但是PostgreSQL怎么会知道你的意思呢?

字符串文字根据您当前的语言环境设置进行解释,特别是lc_time在转换为timestamp或时date.我在这里引用手册:

lc_time(字符串)

设置用于格式化日期和时间的语言环境,例如使用to_char系列函数.可接受的值取决于系统; 有关更多信息,请参见第22.1节.如果此变量设置为空字符串(这是默认值),则该值将以与系统相关的方式从服务器的执行环境继承.

在您的情况下,残缺的时间戳文字1-12-31 23:59:59显然被解释为:

D-MM-YY h24:mi:ss
Run Code Online (Sandbox Code Playgroud)

虽然你希望:

Y-MM-DD h24:mi:ss
Run Code Online (Sandbox Code Playgroud)

3个选项

  1. 设置lc_time为以与您相同的方式解释此类文字的语言环境.不确定是否有.

  2. 用于to_timestamp()以明确定义的方式解释字符串文字 - 独立于当前区域设置.好多了.

    SELECT to_timestamp('1-12-31 23:59:59', 'D-MM-YY h24:mi:ss')
    
    Run Code Online (Sandbox Code Playgroud)
  3. 更好的是,对所有日期时间文字使用ISO 8601格式(YYYY-MM-DD).这与任何语言环境都是明确的.

    SELECT '2001-12-31 23:59:59'::timestamp
    
    Run Code Online (Sandbox Code Playgroud)

重写查询

最后,您的查询开始时有问题.以不同方式处理范围查询.将您的查询重写为:

SELECT d.given_on 
FROM   documents_document d
WHERE  EXTRACT('month' FROM d.given_on) = 1
AND    d.given_on >= '2001-01-01 0:0'
AND    d.given_on <  '2002-01-01 0:0'
ORDER  BY d.created_on DESC;
Run Code Online (Sandbox Code Playgroud)

或者,更简单:

SELECT d.given_on 
FROM   documents_document d
WHERE  d.given_on >= '2001-01-01 0:0'
AND    d.given_on <  '2001-02-01 0:0'
ORDER  BY d.created_on DESC;
Run Code Online (Sandbox Code Playgroud)

您可能会对PostgreSQL 9.2新范围类型感兴趣.