MySQL的null,substring,dual
注:本篇文档是一个大杂烩。
环境
- MySQL 8.0.28
null
我们知道,在SQL语句里, null
是一个特殊的值,它类似于Java里的 null
,表示一个值为空或者未知。
比如一个 person
表,有 name
、 age
等列,其中 age
是 int
类型。如果一个人的年龄未知,那么其 age
如何设置呢?在这里,使用 null
值,就表示这个人的年龄未知。这比设置成一个特定值(比如 0
或 -1
)更合适。
注意: null
和数值 0
,空字符串 ''
是不同的。
关于null,最容易出错的一点是:在判断一个表达式是不是null时,需要注意不是用 xxx = null
,而是 xxx is null
。
现有表 t1
如下:
select c1 is null from t1;
+------------+
| c1 is null |
+------------+
| 0 |
| 1 |
+------------+
2 rows in set (0.01 sec)
可见, xxx is null
是一个布尔表达式,会返回true/false,也就是1/0。
也可以把 xxx is null
用到where条件里:
select * from t1
where c1 is null;
现在问题来了,如果在判断null时,使用了 xxx = null
,结果会是什么呢?
select * from t1
where c1 = null;
可见,结果里一条记录也没有,这是为什么呢?
这是因为,null和其它任何值(包括null值)比较,结果都是null,所以 where c1 = null
永远返回null,也就是说where条件不满足,所以结果里一条记录也没有。
这一点一定要小心,否则很容易出错。
coalesce
coalesce()
函数有两个参数,如果第一个参数不是null,就返回第一个参数,否则返回第二个参数。
select coalesce(1, 2);
+----------------+
| coalesce(1, 2) |
+----------------+
| 1 |
+----------------+
1 row in set (0.01 sec)
上例中,第一个参数不是null,所以返回第一个参数值。
select coalesce(null, 2);
+-------------------+
| coalesce(null, 2) |
+-------------------+
| 2 |
+-------------------+
1 row in set (0.00 sec)
上例中,第一个参数是null,所以返回第二个参数值。
现在,我们用 coalesce()
来验证一下 xxx = null
的返回值:
select coalesce(c1 = null, 2) from t1;
+------------------------+
| coalesce(c1 = null, 2) |
+------------------------+
| 2 |
| 2 |
+------------------------+
2 rows in set (0.00 sec)
可见, xxx = null
的返回值确实是null。
substring
substring()
函数有3个参数:
- 字符串
- 起始下标(从1开始)
- 子串长度
比如:
select substring('abcde', 3, 2);
+--------------------------+
| substring('abcde', 3, 2) |
+--------------------------+
| cd |
+--------------------------+
1 row in set (0.01 sec)
问题又来了:如果下标越界,结果会是什么?
看下面的SQL:
select substring('abcde', 9, 2);
+--------------------------+
| substring('abcde', 9, 2) |
+--------------------------+
| |
+--------------------------+
1 row in set (0.01 sec)
从结果里,似乎看不出来是null还是 ''
,我们用 coalesce()
来判断一下:
select coalesce(substring('abcde', 9, 2), 'zzz');
+-------------------------------------------+
| coalesce(substring('abcde', 9, 2), 'zzz') |
+-------------------------------------------+
| |
+-------------------------------------------+
1 row in set (0.00 sec)
可见,如果 substring()
下标越界了,会返回 ''
,而不是null值。
这一点挺奇怪的,因为我问了DeepSeek和豆包,它们都说下标越界时,返回值是null。
前面提到,判断 ''
和null是不一样的,前者用 =
,后者用 is
。
比如:
select substring('abcde', 9, 1) = substring('hijkl', 9, 1);
+-----------------------------------------------------+
| substring('abcde', 9, 1) = substring('hijkl', 9, 1) |
+-----------------------------------------------------+
| 1 |
+-----------------------------------------------------+
1 row in set (0.00 sec)
如果知道substring不会返回null,那我们就可以全部直接用 =
来判断了(在非null值上使用 is
会报错)。
dual
在上面的例子里,你可能已经发现了:如果是计算一个表达式的值(和表无关),可以直接用 select
而无需 from
,比如:
select 1 + 1;
+-------+
| 1 + 1 |
+-------+
| 2 |
+-------+
1 row in set (0.00 sec)
如果不习惯这种写法,可以使用MySQL提供的一个虚拟表 dual
:
select 1 + 1 from dual;
+-------+
| 1 + 1 |
+-------+
| 2 |
+-------+
1 row in set (0.00 sec)
结果也是一样的。
注:在Db2里的写法是:
select 1 + 1 from sysibm.sysdummy1
考一考
下面SQL的运行结果是什么?
select 1 = null, 1 > null, 1 < null, 1 <> null, 1 is null
答案是:
null null null null 0
下面SQL的运行结果是什么?
select null = null, null > null, null < null, null <> null, null is null
答案是:
null null null null 1
总结:null和其它值(包括null值)比较(大于、小于、等于、不等于),结果都是null,只有 xxx is null
才会返回true/false。