PostgreSQL如何从timestamp with time zone字段提取本地当日时间
报错根因
PostgreSQL 持久化生成列要求表达式必须是*不可变(immutable)*的,即相同输入永远返回相同输出,不受数据库配置、会话时区等外部参数影响。你遇到的两类报错原因如下:
- 首次语法错误:生成列的
AS后仅需写单行列值计算逻辑,不允许传入完整SELECT查询语句 generation expression is not immutable报错:对timestamp with time zone类型做::timestamp转换、EXTRACT取时分秒操作,默认依赖当前会话的时区配置,时区变化会导致计算结果变化,因此PostgreSQL判定该操作为非不可变操作,禁止用于生成列
方案1:创建符合要求的持久化生成列
如果需要直接在原表生成持久化字段,可固定你数据对应的PST时区做转换,此时表达式为不可变,可正常创建:
ALTER TABLE tablename ADD COLUMN stattime time GENERATED ALWAYS AS ( (statdate AT TIME ZONE 'PST')::time ) STORED;
创建完成后直接查询原表stattime字段即可得到12:47:54格式的时间值。
方案2:视图方案对接Rails(你已选择的实现路径)
你现有的视图创建逻辑可优化为固定时区避免后续会话时区变化导致结果异常,优化后的语句如下:
CREATE OR REPLACE VIEW public.view_bp_with_time AS SELECT id, statdate, (statdate AT TIME ZONE 'PST')::time AS stattime, y_axis FROM table_name ORDER BY statdate;
后续接入Rails项目仅需3步:
- 在Rails项目
app/models/目录下新建视图对应的模型文件view_bp_with_time.rb - 模型内写入如下配置:
class ViewBpWithTime < ApplicationRecord self.table_name = 'view_bp_with_time' self.primary_key = 'id' # 标记为只读避免误操作修改数据 def readonly? true end end
- 修改Chartkick渲染代码,直接查询视图取数即可:
<%= line_chart ViewBpWithTime.where(statdate: start..current_date).pluck(:stattime, :y_axis) %>
内容的提问来源于stack exchange,提问作者Greg
相关产品推荐
相关产品推荐

