【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,这样至少日期相减得数字的这个最常见的兼容性问题就不用纠结了。

相关推荐
2301_781571421 天前
Golang格式化输出占位符都有什么_Golang fmt占位符教程【通俗】
jvm·数据库·python
养肥胖虎1 天前
RAG学习笔记(3):区分数据库检索与RAG的使用场景
数据库·ai·rag
_ku_ku_1 天前
数据库系统原理 · 数据库应用开发 · 自学总结
数据库
No8g攻城狮1 天前
【人大金仓】wsl2+ubuntu22.04安装人大金仓数据库V9
java·数据库·spring boot·非关系型数据库
山峰哥1 天前
SQL慢查询调优实战:从全表扫描到索引覆盖的完整复盘
前端·数据库·sql·性能优化
代码中介商1 天前
Redis入门:5大数据类型全解析
数据库·redis·缓存
渣渣盟1 天前
数据库设计范式详解(纯小白版)
数据库·oracle·软考·数据库工程师
夜雪闻竹1 天前
Cursor 对话导入:解析 SQLite 里的宝藏
数据库·sqlite·ai编程
hhb_6181 天前
PL/SQL核心技术难点梳理与实战应用案例解析
数据库·sql
m0_470857641 天前
PHP怎么实现工厂模式_Factory模式编写指南【指南】
jvm·数据库·python