Postgres会自动将日期字段和时间戳字段转换为timestamptz

后端开发 2026-07-09

我有一个基于公用表表达式(CTE)的视图。

create or replace view viewname
as
WITH all_dates AS 
(
SELECT generate_series
    (
        ( SELECT min(date_trunc('day'::text, problem_time))::date AS min 
            FROM tablename)
        , now()::date
        , '1 day'::interval
    )::date AS date_id
)
, ..... rest of view

命令执行时,Postgres生成的视图为

create or replace viewname
as
WITH all_dates AS 
(
SELECT generate_series
    (
        (
            ( SELECT min(date_trunc('day'::text,problem_time))::date AS min
                   FROM tablename))::timestamp with time zone
            , now()::date::timestamp with time zone
            , '1 day'::interval)::date AS date_id
        )
, ..... rest of view

在对带时间戳字段进行筛选并继续深入到CTE结构时,被比较的值被转换为timestamptz。

在我写的地方

where response >= reference

-- response is a timestamp type
-- reference is a timestamp type from some other preceding query

Postgres正在转换为

where response >= reference::timestamp with time zone

我的问题是,为什么会发生这种情况,以及如何防止它?

解决方案

转换之所以发生,是因为不存在函数 generate_series(date, date, interval)。因此你的列会被转换为函数能够接受的类型。Postgres已经在 TIMESTAMP WITH TIME ZONETIMESTAMP [WITHOUT TIME ZONE] 之间任意选取了 TIMESTAMP WITH TIME ZONE

对于后者,没有看到完整的模式和查询,很难说清原因。很可能一个或多个列不是你预期的类型,因此一切都被提升为 TIMESTAMP WITH TIME ZONE,以便比较能够工作。

最后,没有理由在 TIMESTAMPTIMESTAMP WITH TIME ZONE(aka timestamptz)之间取其一。PostgreSQL中这些类型的存储需求相同,你也不会在比较和转换时遇到怪异的边界情况。然而,请记住,所有比较都在客户端设置的时区内进行。因此,如果你的客户端设置为EDT,但另一位客户端在UTC下插入时间戳,那么你对该时间戳所表示的小时数或日期的理解将会不同。

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章