GaussDB(DWS)函数不同写法引发的结果差异

gaussdb,dws,函数,不同,写法,引发,结果,差异 · 浏览次数 : 19

小编点评

## GaussDB(DWS)函数因不同写法引发的结果差异案例 **问题背景:** 用户反馈mysql兼容模式下,以下两条sql的执行结果存在差异: ```sql select greatest(1,2,100,-1,0,nvl(null,0)) select greatest(1,2,100,-1,0,0) ``` **分析:** * **第一条**使用`greatest(1,2,100,-1,0)`函数,并以`text`类型进行排序。 * **第二条**使用`greatest(1,2,100,-1,0,0)`函数,并以`int`类型进行排序。 **问题:** 为什么使用`greatest(1,2,100,-1,0)`函数会出现不同的结果? **答案:** `greatest(1,2,100,-1,0)`函数在不同写法下会根据不同的类型匹配规则进行排序。 **mysql兼容模式下的类型匹配规则:** * **`text`类型**:如果所有输入都是相同的类型,不包括`unknown`类型,那么解析成所输入的相同数据类型。 * **`unknown`类型**:如果所有输入都是`unknown`类型则解析成`text`类型。 * **`int`类型**:如果所有输入都是`unknown`类型,则解析成`int`类型。 * **`enum`类型**:如果存在多种非`unknown`类型,将`enum`类型当做`text`类型,再进行比较。 **具体规则如下:** | 类型范畴 | 解析 `text` 类型 | 解析 `unknown` 类型 | 解析 `int` 类型 | 解析 `enum` 类型 | |---|---|---|---|---| | `text` | 匹配同类型 | 匹配 `text` 类型 | 匹配 `int` 类型 | 匹配 `enum` 类型 | **总结:** 在不同写法情况下,`greatest(1,2,100,-1,0)`函数会根据不同的类型匹配规则进行排序。因此,在使用此函数时,需要注意数据类型,避免使用不当的写法。

正文

本文分享自华为云社区《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)函数不同写法引发的结果差异相似的内容:

GaussDB(DWS)函数不同写法引发的结果差异

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

GaussDB(DWS)条件表达式函数返回错误结果集排查

摘要:条件表达式函数中出现结果集不一致问题,我们首先要考虑是否入参数据类型不一致导致出参不一致。 本文分享自华为云社区《GaussDB(DWS)条件表达式函数返回错误结果集排查》,作者:yd_211369925 。 (一)案例背景 客户使用greatest获取并返回参数列表中值最大的表达式的值,子查

数仓性能调优:如何进行函数下推

摘要:本文主要描述下函数在满足特征的前提下可以把函数属性定义为下推属性。 本文分享自华为云社区《GaussDB(DWS)性能调优:函数下推》,作者:譡里个檔 。 DWS作为MPP架构的数仓产品,其性能优势主要在分布式计算上。默认情况下,DWS为了保证结果的正确性,自定义函数默认属性是不下推的,这会导

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

摘要:本文主要讲解DWS函数出参带出方式。 本文分享自华为云社区《GaussDB(DWS)功能 -- 函数出参 #【玩转PB级数仓GaussDB(DWS)】》,作者:譡里个檔 。 DWS的PL/pgSQL函数/存储过程中有一个特殊的语法PERFORM语法,用于执行语句但是丢弃执行结果的场景,常用于一

浅谈DWS函数出参方式

摘要:DWS的PL/pgSQL函数/存储过程中有一个特殊的语法PERFORM语法,用于执行语句但是丢弃执行结果的场景,常用于一些状态判断的场景。 本文分享自华为云社区《GassDB(DWS)功能 -- 函数出参 #【玩转PB级数仓GaussDB(DWS)】》,作者:譡里个檔。 DWS的PL/pgSQ

云小课|使用SQL加密函数实现数据列的加解密

摘要:数据加密作为有效防止未授权访问和防护数据泄露的技术,在各种信息系统中广泛使用。作为信息系统的核心,GaussDB(DWS)数仓也提供数据加密功能,包括透明加密和使用SQL函数加密。 本文分享自华为云社区《看GaussDB(DWS)如何使用SQL加密函数实现数据列加解密》,作者:Hello EI

详解GaussDB(DWS)中的行执行引擎

本文分享自华为云社区《GaussDB(DWS)行执行引擎详解》,作者:yd_227398895。 1.前言 GaussDB(DWS)包含三大引擎,一是SQL执行引擎,用来解析用户输入的SQL语句,生成执行计划,供执行引擎来执行;二是执行引擎,其中包含了行执行引擎和列执行引擎,执行引擎即查询的执行者,

GaussDB(DWS)性能调优,解决DM区大内存占用问题

本文分享自华为云社区《GaussDB(DWS)性能调优:DM区优化案例——维度表关联条件存在会计期》,作者: O泡果奶~。 当前DM(P1、P3、CBGDM)存在维度表与主表关联时使用会计期作为关联条件,会导致出现大内存占用或未识别数据倾斜的问题 【场景一】f.period_id = 维度表.per

云小课|GaussDB(DWS)数据存储尽在掌控,冷热数据切换自如

阅识风云是华为云信息大咖,擅长将复杂信息多元化呈现,其出品的一张图(云图说)、深入浅出的博文(云小课)或短视频(云视厅)总有一款能让您快速上手华为云。更多精彩内容请单击此处。 摘要: GaussDB(DWS)支持根据业务系统的不同使用需求,对膨胀的数据进行冷热分级管理,将数据按照时间分为热数据、冷数

GaussDB(DWS)现网案例:collation报错

摘要:用户创建hash分布表,使用pbe方式执行使用分布列作为查询条件的语句时报错 本文分享自华为云社区《GaussDB(DWS)现网案例之collation报错》,作者: 你是猴子请来的救兵吗 。 用户创建hash分布表,使用pbe方式执行使用分布列作为查询条件的语句时报错,ERROR: coul