"颗粒度"没对齐——让人费解的CHAR(1)

2024年 6月 18日 62.3k 0

本文为新专栏《那些让人感到"匪夷所思"或者说是让人摸不着头脑的Oracle"特色"设计》第一篇文章,

旨在分享和吐槽,作为羲和(Halo)数据库内核研发在实现Oracle兼容的时候,碰见过的奇奇怪怪的Oracle"特色"。

今天的主题是《"颗粒度"没对齐——让人费解的CHAR(1)类型》。

看到今天的主题,可能有不少的朋友会吐槽一个Oracle的CHAR(1)类型有什么让人费解的这不是简简单单吗?而且CHAR(1)在各个数据库中也都支持的呀?

我想说的是大伙,别着急咱们接下来慢慢看。

一、ORACLE——PL/SQL中CHAR(1)的表现

开门见题,还是以一个例子开头,如果是执行如下的匿名块,Oracle的输出结果是什么呢?

DECLARE
col1 CHAR(1);
BEGIN
col1 := '';
DBMS_OUTPUT.PUT_LINE('Length :'||TO_CHAR(LENGTH(col1)));
IF (col1 IS NULL) THEN
dbms_output.put_line('Treated as NULL');
END IF;
IF (col1 = '') THEN
dbms_output.put_line('Treated as EMPTY STRING');
END IF;
IF (col1 = ' ') THEN
dbms_output.put_line('Treated as space');
END IF;
END;
/

整个匿名块其实非常简单,就是定义了一个名为col1的变量,且变量类型为CHAR(1),接下来被赋值成了 '' ,输出一下当前的长度,接下来就是几个简单的判断,最后输出对应的字符串。建议思考一会…

如果看到这的话,估计有同学会说,所见即所得嘛,既然变量col1被赋值成了'',那么符合col1 = ''这一条件,最后应该输出’Treated as EMPTY STRING’才对。

如果是对Oracle的SQL比较了解的同学,可能会给出col1变量符合 IS NULL的条件,最终应该会输出’Treated as NULL’。

那么最终到底结果如何呢?接下来给出运行结果

"颗粒度"没对齐——让人费解的CHAR(1)-1

可以看到的是最终输出长度为一,最终结果’Treated as space’。

这时候有的同学可能想说:“我先不纠结为什么最后结果是这样的,你刚刚是不是说了‘对Oracle的SQL比较了解’,难道说在SQL层面还有新的花样?”。

接下来咱们来看看Oracle的SQL层面对类型为CHAR(1)的表现。

二、ORACLE——SQL中CHAR(1)的表现

那么当存在一个字段,字段类型为CHAR(1),插入字段值为 '' ,这个时候到底实际的数据值到底是什么呢?

以如下SQL进行测试:

CREATE TABLE ta(col1 CHAR(1));
INSERT INTO ta VALUES('');
SELECT 1,col1 FROM ta WHERE col1 IS NULL;
SELECT 1,col1 FROM ta WHERE col1 = '';
SELECT 1,col1 FROM ta WHERE col1 = ' ';

创建一张名为ta的表,表中有一名为col1的字段,字段类型为CHAR(1),插入一条 '' 数据,接下来使用三条SELECT分别去判断此时col1到底为何值?

建议大家再思考一会…

最终运行结果如下所示:

"颗粒度"没对齐——让人费解的CHAR(1)-2

可以看到的是,最终判定col1不为 '' ,也不为 ' '(空格),而是NULL。

可以看到的是,对于CHAR(1)这个同样的类型,同样的输入值,但是最终的输出,在Oracle的SQL层面和PL/SQL层面完全不一致。

至于这到底算不算是Oracle的bug,就交由诸君定夺。

不过我合理怀疑Oracle数据库研发存在多个团队,SQL层面有一个团队,PL/SQL层面也存在一个团队,

两个团队同时进行研发,两个团队中对于部分重合的内容设计各有各的想法,比如说(CHAR(1)),就像经典的修桥问题,如果用行业黑话来讲就是“颗粒度没对齐”,

这也就是今天的主题 《研发团队"颗粒度"没对齐——让人费解的CHAR(1)类型》。

"颗粒度"没对齐——让人费解的CHAR(1)-3

三、PostgreSQL中CHAR(1)的表现

前面也说到了其实不仅仅只有Oracle支持CHAR类型,那么这块再把PostgreSQL拉过来玩玩。以如下SQL进行测试,

首先是plpgsql

DO $$
DECLARE
col1 CHAR(1);
BEGIN
col1 := '';
raise notice 'Length : %', LENGTH(col1);
IF (col1 IS NULL) THEN
raise notice 'Treated as NULL';
END IF;
IF (col1 = '') THEN
raise notice 'Treated as EMPTY STRING';
END IF;
IF (col1 = ' ') THEN
raise notice 'Treated as space';
END IF;
END;
$$ language plpgsql;

运行结果

"颗粒度"没对齐——让人费解的CHAR(1)-4

接下来是相同的SQL测试

CREATE TABLE ta(col1 CHAR(1));
INSERT INTO ta VALUES('');
SELECT 1,col1 FROM ta WHERE col1 IS NULL;
SELECT 1,col1 FROM ta WHERE col1 = '';
SELECT 1,col1 FROM ta WHERE col1 = ' ';

运行结果:

"颗粒度"没对齐——让人费解的CHAR(1)-5

可以看到的是,在PostgreSQL中如果类型为CHAR(1),且输入时 '' ,那么实际进行匹配的时候,既可以是所见即所得的 '',也可以是 ' '(空格)。

而对于PostgreSQL而言,不管是PL/SQL层面还是SQL层面,它的输出都是一致的,没有割裂的感觉。这是因为PostgreSQL的PL/SQL引擎其实是在原本SQL引擎的基础上实现的。

四、羲和(Halo)数据库

都讲到这了,拉上我们的数据库玩玩。对于羲和(Halo)数据库而言,则是要分模式来测试了。

比如说羲和数据库(PG模式)运行结果如下:

"颗粒度"没对齐——让人费解的CHAR(1)-6

可以看到的是,和PostgreSQL输出结果一致。

接下来是羲和数据库(Oracle模式)运行结果如下:

"颗粒度"没对齐——让人费解的CHAR(1)-7

可以看到的对于羲和数据库Oracle模式而言,对于CHAR(1)类型,如论在何种场景之下,保证了和SQL场景下的输出结果一致。

而对于其他类型比如说VARCHAR2(1)等没有任何歧义的,我们的最终输出结果与Oracle一致.

如下所示:

"颗粒度"没对齐——让人费解的CHAR(1)-8 "颗粒度"没对齐——让人费解的CHAR(1)-9

"颗粒度"没对齐——让人费解的CHAR(1)-10 "颗粒度"没对齐——让人费解的CHAR(1)-11

五、声明

本文为此系列第一篇,如想看到对Oracle功能的吐槽,敬请期待期待。

若文中存在错误或不当之处,敬请指出,以便我进行修正和完善。希望这篇文章能够帮助到各位。

文章转载请联系,谢谢合作。

欢迎大家加入羲和(Halo)产品吐槽群

"颗粒度"没对齐——让人费解的CHAR(1)-12

相关文章

Oracle如何使用授予和撤销权限的语法和示例
Awesome Project: 探索 MatrixOrigin 云原生分布式数据库
下载丨66页PDF,云和恩墨技术通讯(2024年7月刊)
社区版oceanbase安装
Oracle 导出CSV工具-sqluldr2
ETL数据集成丨快速将MySQL数据迁移至Doris数据库

发布评论