三个最常用的杂项:cast() 转类型、if() 三目、ifnull() 兜空。
cast 有一处必须记住:CAST(3.7 AS INTEGER) 这里给 3(砍掉小数),
MySQL 的 CAST(3.7 AS SIGNED) 给 4(四舍五入)——同一个意思不同结果。
Demo 里 if(height >= 170, '高个', '普通') 按身高分类;
ifnull(phone, '未填') 把 null 换成文字。
上一篇查环境,这一篇是「格式转换与取值选择」——报表里天天用的三个。
它们的共同点是「只影响这次查询的输出」,都不改表里的数据。
要真把 null 改掉,得 update(第 7 章讲)。
一、cast:强制转换类型
写法:cast(值 as 类型)。
常用类型这里写 INTEGER/REAL/TEXT,MySQL 写 SIGNED/DECIMAL/CHAR/DATE。
教材里的 CAST(x AS CHAR) 在本沙箱要写成 CAST(x AS TEXT)。
字符串转数字是「能读多少读多少」:'12abc' 给 12,读不动就停。
小数转整数有一处两边不一样:这里(SQLite)直接砍,
3.7 给 3;MySQL 的 SIGNED 是四舍五入,给 4。
最常用的场景其实是排序:字符串 '10' 会排在 '9' 前面,
因为按字面比 1 小于 9。 转成数字才不会。
这一招在清洗「本该是数字却存成文本」的列时天天用。
二、if:三目运算
if(条件, 真值, 假值),跟编程语言里的三目运算一模一样。 条件是 0 或 null 都走假分支。
它比 case when 短,但只能处理两种情况。 三种以上就得用 case when——那个是标准 SQL,
MySQL 和这里都支持。
注意 if 是 MySQL 的方言,标准 SQL 里没有(标准写法是 case when)。
跨库的代码优先用 case when,兼容性更好。
三、ifnull 与 coalesce:null 兜底
ifnull(值, 兜底):值为 null 就给兜底,否则原样返回。 它只接两个参数。
coalesce 能接一串:coalesce(a, b, c) 给「第一个不是 null 的」。
两个以上备选就用 coalesce,只有一个备用时 ifnull 更直观。
它俩都不改表里的数据,只影响这次查询的输出。 要真把 null 改掉,得 update。
这一点很多人会搞混:查询里兜了底,就以为表里已经补上了。
四、三个合起来:一条报表语句
ifnull 补空、if 分类、cast 转显示格式——这三个经常一起出现在同一条 select 里。
但要记住第 23 课那条红线:
这些函数一旦包在 where 的列上,索引就废了。
放在 select 里造列没问题,放在 where 里要当心。
一个折中办法:如果确实要按「分类结果」筛,
先把筛选条件写成能用到索引的形式,再在 select 里做展示。 筛选用原值,展示用函数——
这是最稳的分工。
五、动手 Demo:转类型、分两类、兜空值
Demo 五段:cast 的两种方向、if 分类、ifnull 兜空,最后三个合起来用。
第一段的 3.7 → 3 是这一篇最该带走的一格,因为 MySQL 上同一句给 4。
import _q46 as Q
c = Q.con()
# cast:小数转整数,这里砍、MySQL 四舍五入
c.execute("SELECT CAST('12abc' AS INTEGER) AS a, "
"CAST(3.7 AS INTEGER) AS b, CAST(3.2 AS INTEGER) AS c")
c.execute("SELECT CAST(12 AS TEXT) AS a, CAST('3.5' AS REAL) AS b")
# if:三目运算
c.execute("SELECT name, height, "
"IF(height >= 170, '高个', '普通') AS tag "
"FROM students ORDER BY height DESC LIMIT 6")
# ifnull 与 coalesce
c.execute("SELECT IFNULL(NULL, '默认') AS a, "
"IFNULL('有值', '默认') AS b")
c.execute("SELECT name, IFNULL(phone, '未填') AS phone "
"FROM students WHERE phone IS NULL")
# 三个一起用
c.execute("SELECT name, IFNULL(phone, '未填') AS phone, "
"IF(height >= 170, '高个', '普通') AS tag, "
"CAST(height AS TEXT) AS h FROM students LIMIT 3")
实跑输出:
--------------------------------------------------------------------
第三十课:cast、if、ifnull,三个最常用的杂项函数
--------------------------------------------------------------------
cast:强制转换类型,小数这一处两边不一样
SQL> SELECT CAST('12abc' AS INTEGER) AS a, CAST(3.7 AS INTEGER) AS b,
CAST(3.2 AS INTEGER) AS c
a b c
---------------
12 3 3
(1 行)
**`'12abc'` 转成 12**——能读多少读多少,读不动就停。
**`3.7` 转成 3、`3.2` 也转成 3**,因为这里(SQLite)转整数是「直接砍掉小数」。
**MySQL 的 `CAST(3.7 AS SIGNED)` 给 4**——它是四舍五入,不是砍。
**同一个意思、同一个写法,两个引擎给不同的数,这是很典型的一处。**
**类型名也不一样**:这里写 `INTEGER`/`REAL`/`TEXT`,
**MySQL 写 `SIGNED`/`DECIMAL`/`CHAR`/`DATE`。**
**教材里的 `CAST(x AS CHAR)` 在本沙箱要写成 `CAST(x AS TEXT)`。**
SQL> SELECT CAST(12 AS TEXT) AS a, CAST('3.5' AS REAL) AS b
a b
------------
12 3.50
(1 行)
**数字转字符串、字符串转小数,都正常。** **`cast` 最常用的场景其实是「排序时把字符串当数字」**——
**字符串 `'10'` 排在 `'9'` 前面,转成数字才不会。**
if:三目运算,SQL 里的写法
SQL> SELECT name, height, IF(height >= 170, '高个', '普通') AS tag FROM students
ORDER BY height DESC LIMIT 6
name height tag
---------------------------
黄磊 180.20 高个
刘洋 178.30 高个
杨帆 175.10 高个
周涛 174.00 高个
张伟 172.50 高个
徐明 169.70 普通
(6 行)
**`if(条件, 真值, 假值)`,跟编程语言里的三目运算一样。** **条件是 0 或 null 都走假分支。**
**这比写 `case when` 短,但只能处理两种情况。** **三种以上就得用 `case when`**,那个是标准 SQL,
MySQL 和这里都支持。
ifnull 与 coalesce:null 兜底
SQL> SELECT IFNULL(NULL, '默认') AS a, IFNULL('有值', '默认') AS b
a b
--------------
默认 有值
(1 行)
SQL> SELECT name, IFNULL(phone, '未填') AS phone FROM students WHERE phone IS NULL
name phone
---------------
孙悦 未填
(1 行)
**`ifnull(值, 兜底)`:值为 null 就给兜底,否则原样返回。** **它只接两个参数。**
**`coalesce` 能接一串**:`coalesce(a, b, c)` 给「第一个不是 null 的」。
**两个以上备选就用 `coalesce`,只有一个备选用 `ifnull` 更直观。**
**它俩都不改表里的数据,只影响这次查询的输出。** **要真把 null 改掉,得 `update`。**
三个函数合起来用:一条报表语句
SQL> SELECT name, IFNULL(phone, '未填') AS phone, IF(height >= 170, '高个', '普通') AS tag,
CAST(height AS TEXT) AS h FROM students LIMIT 3
name phone tag h
----------------------------------------
张伟 13800001111 高个 172.5
王芳 13800002222 普通 160.2
李娜 13800003333 普通 165.0
(3 行)
**这三个函数经常一起出现在报表里**:`ifnull` 补空、`if` 分类、`cast` 转显示格式。
**但记住第 23 课那条**:
**这些函数一旦包在 `where` 的列上,索引就废了。** 放在 `select` 里造列没问题,
放在 `where` 里要当心。
第一段 cast。 '12abc' 给 12,3.7 和 3.2 都给 3——这里转整数是砍,不是四舍五入。
第二段反向转换。 12 转成 '12','3.5' 转成 3.50。
第三段 if 分类。 前五个「高个」,
第六个徐明 169.70 是「普通」——两类都出现了,一眼能看出分界在哪儿。
第四段 ifnull。 NULL 换成「默认」,有值原样返回。
第五段三个一起用。 前三个学生:都没有 null 需要兜底,
所以看的是 tag 和 h 这两列——h 是转成文本的身高。
30 秒实验
CAST(3.7 AS INTEGER)在本沙箱和 MySQL 分别给什么?IF(NULL, 'a', 'b')给哪一个?为什么?IFNULL(NULL, NULL)给什么?COALESCE(NULL, NULL)呢?
常见误区
- 以为
cast转整数是四舍五入。 这里砍、MySQL 进,同一句 SQL 两边差 1,而且不报错。 - 在
where里用ifnull(phone, '') = ''找空值。 索引失效, 而且语义上该直接写phone IS NULL。 - 在查询里兜了底,就以为表里补上了。 函数只影响输出,改数据得
update。
自测三问(点开对答案)
1. `CAST(3.7 AS INTEGER)` 在本沙箱和 MySQL 分别给什么? —— 这里给 3(砍掉小数),MySQL 的 `CAST(3.7 AS SIGNED)` 给 4(四舍五入)。 2. `ifnull` 和 `coalesce` 有什么区别? —— `ifnull` 只接两个参数;`coalesce` 可以接一串,返回第一个非 null 的。 3. 为什么字符串排序前要先 `cast` 成数字? —— 字符串按字面比,`'10'` 排在 `'9'` 前面;转成数字才是数值序。内置函数这一章到此结束。下一篇换方向——insert、update、delete,开始改数据。
- ☐ (本篇完,下一篇 7.1 数据修改简介)