GaussDB(DWS)函数不同写法引发的结果差异
本文分享自华为云社区《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) 函数出参带出方式
摘要:本文主要讲解DWS函数出参带出方式. 本文分享自华为云社区<GaussDB(DWS)功能 -- 函数出参 #[玩转PB级数仓GaussDB(DWS)]>,作者:譡里个檔 . DWS的 ...
- 由两个问题引发的对GaussDB(DWS)负载均衡的思考
摘要:GaussDB(DWS)的负载均衡通过LVS+keepAlived实现.对于这种方式,需要思考的问题是,CN的返回结果是否会经过LVS,然后再返回给前端应用?如果经过LVS,那么,LVS会不会成 ...
- 十八般武艺玩转GaussDB(DWS)性能调优:SQL改写
摘要:本文将系统介绍在GaussDB(DWS)系统中影响性能的坏味道SQL及SQL模式,帮助大家能够从原理层面尽快识别这些坏味道SQL,在调优过程中及时发现问题,进行整改. 数据库的应用中,充斥着坏味 ...
- 十八般武艺玩转GaussDB(DWS)性能调优(三):好味道表定义
摘要:表结构设计是数据库建模的一个关键环节,表定义好坏直接决定了集群的有效容量以及业务查询性能,本文从产品架构.功能实现以及业务特征的角度阐述在GaussDB(DWS)的中表定义时需要关注的一些关键因 ...
- 从数据仓库双集群系统模式探讨,看GaussDB(DWS)的容灾设计
摘要:本文主要是探讨OLAP关系型数据库框架的数据仓库平台如何设计双集群系统,即增强系统高可用的保障水准,然后讨论一下GaussDB(DWS)的容灾应该如何设计. 当前社会.企业运行当中,大数据分析. ...
- 探索GaussDB(DWS)的过程化SQL语言能力
摘要:在当前GaussDB(DWS)的能力中主要支持两种过程化SQL语言,即基于PostgreSQL的PL/pgSQL以及基于Oracle的PL/SQL.本篇文章我们通过匿名块,函数,存储过程向大家介 ...
- GaussDB(DWS)网络调度与隔离管控能力
摘要:调度算法是调度器的核心,设计调度算法要充分考虑业务场景和用户需求,没有万能的调度算法,只有合适的调度算法. 本文分享自华为云社区<GaussDB(DWS)网络调度与隔离管控能力>,作 ...
- (转)Javascript匿名函数的写法、传参、递归
(原)http://www.veryhuo.com/a/view/37529.html (转)javascript匿名函数的写法.传参和递归 javascript匿名函数的写法.传参和递归 http: ...
- (转)javascript匿名函数的写法、传参和递归
(原)http://www.veryhuo.com/a/view/37529.html (转)javascript匿名函数的写法.传参和递归 http://www.veryhuo.com 2011-0 ...
- jQuery扩展插件和拓展函数的写法
<script type="text/JavaScript"> //jQuery插件的写法(需要传入操作对象) ;(function ...
随机推荐
- 毕业三年,月薪30K,我想跟你聊聊!
大家好,我是冰河~~ 很多读者私信问我,自己工作三年多了,随着工作年限的不断增长,感觉自己的技术水平与自己的工作年限严重不符.想跳槽出去换个新环境吧,又感觉自己的能力达不到心仪公司的标准,即使投了简历 ...
- matlab快速入门笔记
命名规则: clc:清除命令行的所有命令 clear all:清除所有工作区的内容 注释:两个% + 空格 %% matlab的数据类型 1.数字 3 3 * 5 3 / 5 3 + 5 3 - 5 ...
- 洛谷P3392 涂国旗(暴力枚举)
# 涂国旗 ## 题目描述 某国法律规定,只要一个由 $N \times M$ 个小方块组成的旗帜符合如下规则,就是合法的国旗.(毛熊:阿嚏--) - 从最上方若干行(至少一行)的格子全部是白色的: ...
- Python 潮流周刊#24:no-GIL 提案正式被采纳了!
你好,我是猫哥.这里每周分享优质的 Python.AI 及通用技术内容,大部分为英文.标题取自其中两则分享,不代表全部内容都是该主题,特此声明. 微信 | 博客 | 邮件 | Github | Tel ...
- alibaba fastjson的JsonObject有序的实现和源码分析
介绍 FastJson是阿里巴巴的开源JSON解析库,它可以解析JSON格式的字符串,支持将Java Bean序列化为JSON字符串,也可以从JSON字符串反序列化到JavaBean.在使用的过程中, ...
- AI歌姬,C位出道,基于PaddleHub/Diffsinger实现音频歌声合成操作(Python3.10)
懂乐理的音乐专业人士可以通过写乐谱并通过乐器演奏来展示他们的音乐创意和构思,但不识谱的素人如果也想跨界玩儿音乐,那么门槛儿就有点高了.但随着人工智能技术的快速迭代,现在任何一个人都可以成为" ...
- typeid关键词
typeid是c++的关键字,typeid操作符的返回结果是名为type_info的标准库类型的对象的引用(在头文件typeinfo中定义) ISO C++标准并没有确切定义type_info,它的确 ...
- canvas实现动态替换人物的背景颜色
起因 今天遇见一个特别有意思的小功能. 就是更换人物图像的背景颜色. 大致操作步骤就是:点击人物-实现背景颜色发生变化 将图片绘画到canvas画布上 我们需要将图片绘制到canvas画布上. 这样做 ...
- Android RTL 语言适配
RTL 语言,即 right to left language,也就是右对齐的语言,与一般语言按照左对齐的方式不同,需要进行特别适配. AndroidManifest.xml 文件中,增加 andro ...
- C语言,可爱的小明特别喜欢爬楼梯,他有的时候一次爬一个台阶,有的时候一次爬两个台阶,有的时候一次爬三个台阶。如果这个楼梯有n个台阶,小明一共有多少种爬法呢?n值从键盘输入。
/* 开发者:慢蜗牛 开发时间:2020.5.28 程序功能:小明爬楼梯 */ #include<stdio.h> int taijie(int n); long taijie(int n ...