【GaussDB】GaussDB506版本A模式中的date类型

【GaussDB】GaussDB506版本A模式中的date类型

GuassDB 在506.0版本中引入了一个新的数据类型,datea,用于兼容ORACLE的date类型。而在此版本前,GaussDB只是在ORACL兼容模式下,把位于数据类型位置的date,转换成了timestamp(0) without timezone。虽然timestamp(0)和ORACLE的date都是精确到秒,但是两者仍有诸多差异。在边上修修补补对齐行为,还要考虑原本timestamp类型行为的对齐,存在很多矛盾。所以GaussDB干脆就直接新增了一个类型,不再折腾原本的timestamp了。

GaussDB官方文档: GaussDB文档中心/集中式版Oracle兼容性说明/兼容性说明/SQL的基本元素/数据类型

启用date默认映射到datea

修改参数mapping_date_to_datea=on,重启数据库,SQL解析时就会把date类型转换成datea类型。

注:新安装的506.0 SPC0100版本中,该参数是默认开启的。

影响点

  1. SQL中DATE类型的语义识别
    之前版本中,
sql 复制代码
create table t1(a date); -> create table t1(a timestamp(0) without time zone);
select cast(sysdate as date) -> select cast(sysdate as timestamp(0) without time zone);

启用datea后

sql 复制代码
create table t1(a date); -> create table t1(a datea);
select cast(sysdate as date) -> select cast(sysdate as datea);
  1. 默认输出的文本格式
sql 复制代码
gaussdb=# select '2022-01-01 22:01:23'::timestamp(6)::datea;
         datea          
------------------------
 2022-01-01 22:01:23 AD
(1 row)

gaussdb=# select trunc('2022-01-01 22:01:23'::timestamp(6)::datea);
         trunc          
------------------------
 2022-01-01 00:00:00 AD
(1 row)

gaussdb=# 

ORACLE里的DATE格式在sqlplus中的输出受会话中nls_date_format参数的影响,而gaussdb则为固定格式 。

相比自带的timestamp类型,秒后面没有小数了,但相比ORACLE的date类型,多了个表示公元前后的标识AD/BC,而ORACLE则是在前面加负号表示公元前(需alter session set nls_Date_format='syyyy-mm-dd hh24:mi:ss';才能显示)。

  1. 实际存储
sql 复制代码
gaussdb=# select timestamp_send('2022-01-01 22:01:23'::timestamp(6));
   timestamp_send   
--------------------
 \x0002778b326412c0
(1 row)

gaussdb=# select datea_send('2022-01-01 22:01:23'::timestamp(6)::datea);
     datea_send     
--------------------
 \x0002778b326412c0
(1 row)

可以发现datea的存储格式其实还是和timestamp类型一致,因此并不会因为不记录秒后小数而节省存储空间。

  1. 系统函数映射
  • sysdate
mapping_date_to_datea a_format_dev_version a_format_date_timestamp sysdate实际表达式 数据类型 数据输出格式示例
on s7 on sysdate_a() datea 2025-06-13 11:00:44 AD
on s7 off sysdate_a() datea 2025-06-13 11:00:44 AD
on s1 on sysdate_a() datea 2025-06-13 11:00:44 AD
on s1 off sysdate_a() datea 2025-06-13 11:00:44 AD
off s7 on (clock_timestamp())::timestamp(0) without time zone timestamp 2025-06-13 11:00:44.000000
off s7 off (clock_timestamp())::timestamp(0) without time zone timestamp 2025-06-13 11:00:44.000000
off s2-s6 on (pg_systimestamp())::timestamp(0) without time zone timestamp 2025-06-13 11:00:44.000000
off s2-s6 off (pg_systimestamp())::timestamp(0) without time zone timestamp 2025-06-13 11:00:44.000000
off s1 on (pg_systimestamp())::timestamp(0) without time zone timestamp 2025-06-13 11:00:44.000000
off s1 off (pg_systimestamp())::timestamp(0) without time zone timestamp 2025-06-13 11:00:44.000000
  • current_date
mapping_date_to_datea a_format_dev_version a_format_date_timestamp current_date实际表达式 数据类型 数据输出格式示例
on s7 on pg_systimestamp())::datea datea 2025-06-13 11:00:44 AD
on s7 off pg_systimestamp())::datea datea 2025-06-13 11:00:44 AD
on s1 on pg_systimestamp())::datea datea 2025-06-13 11:00:44 AD
on s1 off pg_systimestamp())::datea datea 2025-06-13 11:00:44 AD
off s7 on ('now'::text)::timestamp(0) without time zone timestamp 2025-06-13 11:00:44.000000
off s7 off ('now'::text)::timestamp(0) without time zone timestamp 2025-06-13 11:00:44.000000
off s2-s6 on ('now'::text)::timestamp(0) without time zone timestamp 2025-06-13 11:00:44.000000
off s2-s6 off ('now'::text)::timestamp(0) without time zone timestamp 2025-06-13 11:00:44.000000
off s1 on (pg_systimestamp())::timestamp(0) without time zone timestamp 2025-06-13 11:00:44.000000
off s1 off text_date('now'::text) "date" 2025-06-13

映射到不同的函数,其查询结果的值会与事务、跨语句、执行次数等行为存在相关性,这是老生常谈的问题,本文暂不展开,可参考PG的文档或问AI。

  1. 部分表达式的行为变化
    开启后,默认情况下 date'2022-01-01' 这样的用法会报错,因为nls_date_format的默认值是DD-MON-RR,需要修改参数nls_date_format='yyyy-mm-dd'才能正常执行,这里和ORACLE产生了兼容性差异,ORACLE的 date'2022-01-01'这种用法与nls_date_format参数无关,只能使用syyyy-mm-dd的格式。
sql 复制代码
gaussdb=# select date'2022-12-13';
ERROR:  invalid value "22-12-13" for "MON"
LINE 1: select date'2022-12-13';
                   ^
DETAIL:  The given value did not match any of the allowed values for this field.
CONTEXT:  referenced column: datea
gaussdb=# set nls_date_format='yyyy-mm-dd';
SET
gaussdb=# select date'2022-12-13';
         datea          
------------------------
 2022-12-13 00:00:00 AD
(1 row)

gaussdb=# 
  1. 操作符变化
sql 复制代码
gaussdb=# select '2022-01-01 22:01:23'::timestamp(6)::datea -'2021-01-01 21:01:23'::timestamp(6)::datea;
     ?column?     
------------------
 365.041666666667
(1 row)

gaussdb=# select '2022-01-01 22:01:23'::timestamp(6) -'2021-01-01 21:01:23'::timestamp(6);
           ?column?            
-------------------------------
 +000000365 01:00:00.000000000
(1 row)

gaussdb=# 

最重要的就是两个日期相减了,原本的timestamp相减只能返回interval类型,而datea相减能返回numeric类型,行为兼容ORACLE。

  1. 数据导入

    原本timestamp可以直接以文本方式导入,开启后,对于datea类型必须指定datea_format格式(oracle的sqlldr也要指定日期格式)

  2. 函数易变性

    另外,还有一个参数 modify_function_property,新装的默认值为"3257,5562,4164,4073",

    表示把下面这4个函数的易变性从immutable改成stable

  • pg_catalog.current_timestamp(numeric)
  • pg_catalog.text_timestamp(text)
  • pg_catalog.text_date(text)
  • pg_catalog.DBTimezone()

因为date相关的表达式在不同GUC参数配置下会对应到不同的表达式,而上面这些函数的易变性可以调整,就增加了影响结果的因素。

总结

如果习惯了之前openGauss/GaussDB版本把date处理成timestamp(0),则建议在506.0版本中关闭mapping_date_to_datea,因为这些行为变化实在太多了,可能现有应用程序代码要排查的点太多。但如果是刚开始使用这个版本,可以开启mapping_date_to_datea,这样至少日期相减得数字的这个最常见的兼容性问题就不用纠结了。

相关推荐
想做后端的前端2 小时前
Redis中的Lua使用
数据库·redis·lua
小锋学长生活大爆炸2 小时前
【工具】免费的文本读写API
java·数据库·mysql
晓风残月淡2 小时前
mysql数据库完整备份恢复方案(二)
数据库·mysql·adb
l1t2 小时前
DeepSeek总结的Turso的CTE支持情况
数据库·sqlite·turso
重生之绝世牛码2 小时前
Linux软件安装 —— ClickHouse集群安装(集成Zookeeper)+ chproxy负载均衡
大数据·linux·数据库·clickhouse·软件安装·clickhouse集群安装·clickhouse负载均衡
l1t2 小时前
修改德哥的PostgreSQL求解数独SQL在cedardb上运行
数据库·sql·postgresql·cedardb
想做一只开心的菜鸡2 小时前
DARTS#01 | Tournament Sort算法 | MySQL深度翻页优化技巧 | 论文ByteSlice Review
数据库·mysql·算法
一只自律的鸡3 小时前
【MySQL】第八章 数据类型
数据库·mysql
算法小菜鸟成长心得3 小时前
postgresql18 版本,使用navicate15版本出现不兼容问题
数据库