本文分享自华为云社区《GaussDB(DWS)函数结果差异案例之greatest》,作者: 你是猴子请来的救兵吗。

GaussDB(DWS)支持多种兼容模式,为了兼容目标数据库,各模式之间或多或少存在一些行为差异。这里分享一个mysql兼容模式下的表达式函数因不同写法引发的结果差异案例。

问题背景

问题版本 GaussDB 8.1.1

问题描述

用户反馈mysql兼容模式下,以下两条sql的执行结果存在差异:

select greatest(1,2,100,-1,0,nvl(null,0)) 出来的结果是 2

select greatest(1,2,100,-1,0) 出来结果是 100

场景再现

mysql=# select greatest(1,2,100,-1,nvl(null,0));

greatest

----------

2

(1 row)

mysql=# select greatest(1,2,100,-1,0,0);

greatest

----------

100

(1 row)

根因分析

1,不知道小伙伴们有没有注意到,这两个结果集的显示一个是靠左的一个是靠右的;ok,我们先来确认下这两个结果的数据类型:

mysql=# select pg_typeof(greatest(1,2,100,-1,nvl(null,0)));

pg_typeof

-----------

text

(1 row)

mysql=# select pg_typeof(greatest(1,2,100,-1,0));

pg_typeof

-----------

integer

(1 row)

2,依靠pg_typeof我们拿到了返回结果的数据类型;这就说明第一条语句是以text类型进行排序选择最大值的,依次为(‘0’,‘1’,’-1’,‘100’,‘2’),因此我们得到最大值是字符串类型的’2’。

0

1

-1

100

2

3,依次类推,第二条语句是以int类型进行排序选择最大值的,依次为(-1,0,1,2,100),因此我们得到最大值是数值类型的100。

-1

0

1

2

100

4,表达式函数greatest的返回类型是基于入参类型确定的,这里的差异是由于第五个入参类型导致的结果差异。

mysql=# select pg_typeof(nvl(null,0));

pg_typeof

-----------

text

(1 row)

mysql=# select pg_typeof(0);

pg_typeof

-----------

integer

(1 row)

5,而nvl/greatest之所以会出现不同的返回类型,是由mysql兼容模式下的类型匹配规则决定的。

具体规则可参考:UNION,CASE和相关构造

修改建议

针对此差异场景,建议在不确定返回类型时显式指定其入参类型,将nvl(null,0)改为nvl(null,0)::int,这样结果就是已int排序的,与另一台语句预期相符。

mysql=# select greatest(1,2,100,-1,nvl(null,0)::int);

greatest

----------

100

(1 row)

知识剖析

SQL UNION构造把不相同的数据类型进行匹配输出为统一的数据类型结果集。因为SELECT UNION语句中的所有查询结果必须在一列里显示出来,所以每个SELECT子句中的元素类型必须相互匹配并转换成一个统一的数据类型。同样的要求广泛存在于 UNION、ARRAY 和 CASE、COALESCE、IF、IFNULL 和 GREATEST、LEAST 和 NVL 等表达式和函数中。

GaussDB(DWS)支持多种兼容模式,不同兼容模式下的类型匹配规则也不尽相同。为了便于理解,这里仅以mysql兼容模式下 IFNULL 的类型匹配规则进行举例说明,它与 GREATEST 在mysql兼容模式下的规则是一致的。

规则1: 如果所有输入都是相同的类型,不包括unknown类型,那么解析成所输入的相同数据类型。

mysql=# select pg_typeof(1),pg_typeof(2);

pg_typeof | pg_typeof

-----------+-----------

integer | integer

(1 row)

mysql=# select ifnull(1,2),pg_typeof(ifnull(1,2));

ifnull | pg_typeof

--------+-----------

1 | integer

(1 row)

规则2: 如果所有输入都是unknown类型则解析成text类型。(常量字符串就是unknow类型)

mysql=# select pg_typeof('1'),pg_typeof('2');

pg_typeof | pg_typeof

-----------+-----------

unknown | unknown

(1 row)

mysql=# select ifnull('1','2'),pg_typeof(ifnull('1','2'));

ifnull | pg_typeof

--------+-----------

1 | text

(1 row)

规则3: 如果输入是unknown类型和某一非unknown类型,则解析成该非unknown类型。

mysql=# select pg_typeof(current_date),pg_typeof('20230801');

pg_typeof | pg_typeof

-----------+-----------

date | unknown

(1 row)

mysql=# select ifnull(current_date,'20230801'),pg_typeof(ifnull(current_date,'20230801'));

ifnull | pg_typeof

------------+-----------

2023-08-10 | date

(1 row)

规则4: 如果存在多种非unknown类型,将enum类型当做text类型,再进行比较。

mysql=# create type gender as enum('boy','girl');

CREATE TYPE

mysql=# select pg_typeof('boy'::gender),pg_typeof('girl'::varchar);

pg_typeof | pg_typeof

-----------+-------------------

gender | character varying

(1 row)

mysql=# select ifnull('boy'::gender,'girl'::varchar),pg_typeof(ifnull('boy'::gender,'girl'::varchar));

ifnull | pg_typeof

--------+-----------

boy | text

(1 row)

规则5: 如果输入类型是同一个类型范畴,则选择该类型的优先级较高的类型。如果是不同的类型范畴,则解析成text类型。

--相同类型范畴

mysql=# select pg_typeof(1),pg_typeof(2.0);

pg_typeof | pg_typeof

-----------+-----------

integer | numeric

(1 row)

mysql=# select ifnull(1,2.0),pg_typeof(ifnull(1,2.0));

ifnull | pg_typeof

--------+-----------

1 | numeric

(1 row)

--不同类型范畴

mysql=# select pg_typeof(1),pg_typeof(current_date);

pg_typeof | pg_typeof

-----------+-----------

integer | date

(1 row)

mysql=# select ifnull(1,current_date),pg_typeof(ifnull(1,current_date));

ifnull | pg_typeof

--------+-----------

1 | text

(1 row)

规则6: 把所有输入转换为所选的类型。如果从给定的输入到所选的类型没有隐式转换则失败。

--json不存在到text的隐式转换

mysql=# select pg_typeof(1),pg_typeof('{"a":1}'::json);

pg_typeof | pg_typeof

-----------+-----------

integer | json

(1 row)

mysql=# select ifnull(1,'{"a":1}'::json),pg_typeof(ifnull(1,'{"a":1}'::json));

ERROR: IFNULL could not convert type json to text

LINE 1: select ifnull(1,'{"a":1}'::json),pg_typeof(ifnull(1,'{"a":1}...

^

CONTEXT: referenced column: ifnull

--可以尝试显式指定类型转换

mysql=# select ifnull(1,'{"a":1}'::json::text);

ifnull

--------

1

(1 row)

点击关注,第一时间了解华为云新鲜技术~

GaussDB(DWS)函数不同写法引发的结果差异的更多相关文章

  1. 一文详解数仓GaussDB(DWS) 函数出参带出方式

    摘要:本文主要讲解DWS函数出参带出方式. 本文分享自华为云社区<GaussDB(DWS)功能 -- 函数出参 #[玩转PB级数仓GaussDB(DWS)]>,作者:譡里个檔 . DWS的 ...

  2. 由两个问题引发的对GaussDB(DWS)负载均衡的思考

    摘要:GaussDB(DWS)的负载均衡通过LVS+keepAlived实现.对于这种方式,需要思考的问题是,CN的返回结果是否会经过LVS,然后再返回给前端应用?如果经过LVS,那么,LVS会不会成 ...

  3. 十八般武艺玩转GaussDB(DWS)性能调优:SQL改写

    摘要:本文将系统介绍在GaussDB(DWS)系统中影响性能的坏味道SQL及SQL模式,帮助大家能够从原理层面尽快识别这些坏味道SQL,在调优过程中及时发现问题,进行整改. 数据库的应用中,充斥着坏味 ...

  4. 十八般武艺玩转GaussDB(DWS)性能调优(三):好味道表定义

    摘要:表结构设计是数据库建模的一个关键环节,表定义好坏直接决定了集群的有效容量以及业务查询性能,本文从产品架构.功能实现以及业务特征的角度阐述在GaussDB(DWS)的中表定义时需要关注的一些关键因 ...

  5. 从数据仓库双集群系统模式探讨,看GaussDB(DWS)的容灾设计

    摘要:本文主要是探讨OLAP关系型数据库框架的数据仓库平台如何设计双集群系统,即增强系统高可用的保障水准,然后讨论一下GaussDB(DWS)的容灾应该如何设计. 当前社会.企业运行当中,大数据分析. ...

  6. 探索GaussDB(DWS)的过程化SQL语言能力

    摘要:在当前GaussDB(DWS)的能力中主要支持两种过程化SQL语言,即基于PostgreSQL的PL/pgSQL以及基于Oracle的PL/SQL.本篇文章我们通过匿名块,函数,存储过程向大家介 ...

  7. GaussDB(DWS)网络调度与隔离管控能力

    摘要:调度算法是调度器的核心,设计调度算法要充分考虑业务场景和用户需求,没有万能的调度算法,只有合适的调度算法. 本文分享自华为云社区<GaussDB(DWS)网络调度与隔离管控能力>,作 ...

  8. (转)Javascript匿名函数的写法、传参、递归

    (原)http://www.veryhuo.com/a/view/37529.html (转)javascript匿名函数的写法.传参和递归 javascript匿名函数的写法.传参和递归 http: ...

  9. (转)javascript匿名函数的写法、传参和递归

    (原)http://www.veryhuo.com/a/view/37529.html (转)javascript匿名函数的写法.传参和递归 http://www.veryhuo.com 2011-0 ...

  10. jQuery扩展插件和拓展函数的写法

    <script type="text/JavaScript">            //jQuery插件的写法(需要传入操作对象)        ;(function ...

随机推荐

  1. js数据结构--散列表

    <!DOCTYPE html> <html> <head> <title></title> </head> <body&g ...

  2. camerabin error:"Internal data stream error,使用QT打开MIPI摄像头

    使用QT自带的QCamera打开MIPI摄像头 遇到:camerabin error:"Internal data stream error 降低分辨率为640*480 TRANSLATE ...

  3. 银河麒麟V10 SP1忘记账户密码后重置/更改账户密码

    开机进入选择界面,按下键盘E键 光标通过键盘上下左右键移到linux行最后一句(此处是seurity=kysec后) 输入空格 console=tty1 single 按下F10键,等待重启 输入pa ...

  4. Java面向对象(高级)

    1.类变量 类变量是被类的所有实例共享的. 类变量具体放的位置在哪?在内存中的那个区域,这和jdk的版本是有关的 静态变量在类加载的时候就生成了,即使没有创建类实例也能访问,当然通过实例来实现 类变量 ...

  5. CodeTON Round 4 (Div. 1 + Div. 2)C

    C. Make It Permutation 我们希望尽可能少地进行操作可以使代价最小,我们如果要排列的话,那些重复的元素我们无论如何都要进行删除的,所以我们可以先把去重的代价计算出来,然后依次枚举排 ...

  6. LooklessControl

    Lookless controls vs User Controls. Lookless controls usage patterns(LooklessControl与UserControl的比较. ...

  7. SpringBoot数据响应、分层解耦、三层架构

    响应数据 @ResponseBody 类型:方法注解.类注解 位置:Controller方法.类上 作用:将方法返回值直接响应,如果返回值类型是 实体对象/集合 ,将会转换为json格式响应 说明:@ ...

  8. html5学习内容-6(flex)

    弹性布局–flex (一)视口单位主要包括以下4个: vw:1vw等于视口宽度的1% vh:1vh等于视口高度的1% vmin:选取vm和vh中最小的那个 vmax:选取vm和vh中最大的那个 常用于 ...

  9. NativeBuffering,一种高性能、零内存分配的序列化解决方案[性能测试篇]

    第一版的NativeBuffering([上篇].[下篇])发布之后,我又对它作了多轮迭代,对性能作了较大的优化.比如确保所有类型的数据都是内存对齐的,内部采用了池化机器确保真正的"零内存分 ...

  10. coco漫画获取隐藏的图片链接

    网站分析 打开目标网站:https://www.cocomanhua.com/, 随便打开一部漫画: https://www.cocomanhua.com/10330/1/205.html F12 打 ...