Kodewick
第 6 课,共 21 课目录

计算、函数和 CASE

第 6 课,共 21 课 · 第 1 部分 · 查数据 · 约 15 分钟

SELECT 后面不只能写列名,还能写一个算式。每件商品的库存值多少钱?价格乘库存:

main.sql
1SELECT name, price, stock, price * stock2FROM products;
输出
namepricestockprice * stock
笔记本4.50120540.00
中性笔(10 支)6.0080480.00
双肩包39.9015598.50
水杯12.0040480.00
耳机59.0010590.00
台灯25.0000.00
数据线8.502001700.00
咖啡杯9.9060594.00
手机壳15.0035525.00
帆布袋11.0025275.00
10 行

结果多了一列,每一行都用这一行自己的价格和库存算一遍。表里的数据没有变,这一列只出现在结果里。

列上做算术

加减乘除写作 +、-、*、/,先乘除后加减,括号先算。打八折以后的价格:

main.sql
1SELECT name, price, price * 0.8, price / 32FROM products3WHERE category = '文具';
输出
namepriceprice * 0.8price / 3
笔记本4.503.6001.500000
中性笔(10 支)6.004.8002.000000
2 行

价格本来有两位小数,乘 0.8 以后变成三位(3.600)。/ 的结果带小数,MySQL 默认比原来多给 4 位,所以 4.50 除以 3 显示成 1.500000;别的数据库里,两个整数相除可能只得到整数部分。

AS:给列起名字

算出来的列,列名就是那个算式,又长又难看。用 AS 起一个名字,这叫别名:

main.sql
1SELECT name, price * stock AS stock_value2FROM products3ORDER BY stock_value DESC, id;
输出
namestock_value
数据线1700.00
双肩包598.50
咖啡杯594.00
耳机590.00
笔记本540.00
手机壳525.00
中性笔(10 支)480.00
水杯480.00
帆布袋275.00
台灯0.00
10 行

ORDER BY 可以用这个别名。中性笔和水杯都是 480.00,再按 id 排,顺序才定得下来。别名习惯用英文小写,几个词之间用下划线,不要有空格。

可是 WHERE 里用不了别名:

main.sql
1SELECT name, price * stock AS stock_value2FROM products3WHERE stock_value > 590;
输出
ERROR 1054 (42S22): Unknown column 'stock_value' in 'where clause'

没有叫「stock_value」的列(WHERE 里不能用 SELECT 里起的别名)。检查一下列名有没有写错;如果它是一段文字,要加引号:'stock_value'。

WHERE 比 SELECT 先做,那时候还没有 stock_value 这一列,所以说不认识它。在 WHERE 里把算式再写一遍:WHERE price * stock > 590。第 10 课会把一条查询各部分的先后顺序讲清楚。

ROUND:四舍五入

ROUND(数, 位数) 四舍五入到几位小数;不写位数就是到整数:

main.sql
1SELECT name, price, ROUND(price), ROUND(price * 0.85, 2) AS sale_price2FROM products3WHERE price > 20;
输出
namepriceROUND(price)sale_price
双肩包39.904033.92
耳机59.005950.15
台灯25.002521.25
3 行

ROUND 这样的东西叫函数:名字后面跟括号,括号里是要处理的值,用逗号隔开。

文字函数

处理文字常用的几个:CONCAT 把几段文字接起来,UPPER 把英文字母变大写,LENGTH 算长度:

main.sql
1SELECT CONCAT(name, '(', city, ')') AS who, UPPER(email) AS email2FROM customers3WHERE id <= 3;
输出
whoemail
林晓(上海)[email protected]
王磊(北京)[email protected]
陈静(上海)NULL
3 行

陈静没有邮箱,UPPER(NULL) 还是 NULL。CONCAT 也一样,接上一个 NULL,整个结果就是 NULL。别的数据库常用 || 接文字(name || city),MySQL 里 || 默认是「或」的意思,所以这里用 CONCAT。

数长度要小心:LENGTH 数的是字节,一个汉字占 3 个字节;数字数要用 CHAR_LENGTH:

main.sql
1SELECT name, LENGTH(name), CHAR_LENGTH(name)2FROM products3WHERE category = '厨房';
输出
nameLENGTH(name)CHAR_LENGTH(name)
水杯62
咖啡杯93
2 行

CASE:按条件给不同的值

CASE 像一串「如果……就……」:从上往下看每个 WHEN,第一个成立的,用它的 THEN 后面的值;都不成立,用 ELSE 的值。最后写 END。按库存给商品标个状态:

main.sql
1SELECT name, stock,2    CASE3        WHEN stock = 0 THEN '缺货'4        WHEN stock < 20 THEN '快卖完了'5        ELSE '有货'6    END AS stock_status7FROM products;
输出
namestockstock_status
笔记本120有货
中性笔(10 支)80有货
双肩包15快卖完了
水杯40有货
耳机10快卖完了
台灯0缺货
数据线200有货
咖啡杯60有货
手机壳35有货
帆布袋25有货
10 行
先猜一猜

15 元的手机壳,label 是什么?

1SELECT name,2    CASE3        WHEN price < 50 THEN '便宜'4        WHEN price < 20 THEN '很便宜'5        ELSE '贵'6    END AS label7FROM products8WHERE price = 15;

别漏了最后的 END:漏了它,MySQL 读到 AS 还在等 END,就会报语法错误 ERROR 1064。

练一练

写好查询,点检查。提示随便看,实在想不出来再看答案。

练习 1

库存值多少钱

查出数码类商品的 name 和库存总值 stock_value(价格乘库存)两列,按 id 排。

要显示
namestock_value
耳机590.00
台灯0.00
数据线1700.00
手机壳525.00
4 行
exercise1.sql
1SELECT name, price, stock2FROM products3WHERE category = '数码';
输出
点「运行」或按 Ctrl+Enter
练习 2

打八五折

箱包类商品打八五折。显示 name、price 和 sale_price 三列,sale_price 四舍五入到 2 位小数,按 id 排。

要显示
namepricesale_price
双肩包39.9033.92
帆布袋11.009.35
2 行
exercise2.sql
1SELECT name, price2FROM products3WHERE category = '箱包';
输出
点「运行」或按 Ctrl+Enter
练习 3

价格档次

给每件商品标档次,显示 name、price、price_level 三列:低于 10 的是 便宜,10 到 30 之间(不到 30)的是 中等,其余是 贵,按 id 排。

要显示
namepriceprice_level
笔记本4.50便宜
中性笔(10 支)6.00便宜
双肩包39.90贵
水杯12.00中等
耳机59.00贵
台灯25.00中等
数据线8.50便宜
咖啡杯9.90便宜
手机壳15.00中等
帆布袋11.00中等
10 行
exercise3.sql
1SELECT name, price2FROM products;
输出
点「运行」或按 Ctrl+Enter

这一课学会了

  • SELECT 里可以写算式,每一行算一遍;表里的数据不变。
  • AS 名字 给列起别名,ORDER BY 里可以用它,WHERE 里不行。
  • ROUND(数, 位数) 四舍五入;CONCAT 接文字,UPPER 变大写,LENGTH 数字节、CHAR_LENGTH 数字数。
  • 函数碰到 NULL,结果通常也是 NULL。
  • CASE WHEN … THEN … ELSE … END 用第一个成立的 WHEN,别漏了 END。