计算、函数和 CASE
SELECT 后面不只能写列名,还能写一个算式。每件商品的库存值多少钱?价格乘库存:
1SELECT name, price, stock, price * stock2FROM products;
| name | price | stock | price * stock |
|---|---|---|---|
| 笔记本 | 4.50 | 120 | 540.00 |
| 中性笔(10 支) | 6.00 | 80 | 480.00 |
| 双肩包 | 39.90 | 15 | 598.50 |
| 水杯 | 12.00 | 40 | 480.00 |
| 耳机 | 59.00 | 10 | 590.00 |
| 台灯 | 25.00 | 0 | 0.00 |
| 数据线 | 8.50 | 200 | 1700.00 |
| 咖啡杯 | 9.90 | 60 | 594.00 |
| 手机壳 | 15.00 | 35 | 525.00 |
| 帆布袋 | 11.00 | 25 | 275.00 |
结果多了一列,每一行都用这一行自己的价格和库存算一遍。表里的数据没有变,这一列只出现在结果里。
列上做算术
加减乘除写作 +、-、*、/,先乘除后加减,括号先算。打八折以后的价格:
1SELECT name, price, price * 0.8, price / 32FROM products3WHERE category = '文具';
| name | price | price * 0.8 | price / 3 |
|---|---|---|---|
| 笔记本 | 4.50 | 3.600 | 1.500000 |
| 中性笔(10 支) | 6.00 | 4.800 | 2.000000 |
价格本来有两位小数,乘 0.8 以后变成三位(3.600)。/ 的结果带小数,MySQL 默认比原来多给 4 位,所以 4.50 除以 3 显示成 1.500000;别的数据库里,两个整数相除可能只得到整数部分。
AS:给列起名字
算出来的列,列名就是那个算式,又长又难看。用 AS 起一个名字,这叫别名:
1SELECT name, price * stock AS stock_value2FROM products3ORDER BY stock_value DESC, id;
| name | stock_value |
|---|---|
| 数据线 | 1700.00 |
| 双肩包 | 598.50 |
| 咖啡杯 | 594.00 |
| 耳机 | 590.00 |
| 笔记本 | 540.00 |
| 手机壳 | 525.00 |
| 中性笔(10 支) | 480.00 |
| 水杯 | 480.00 |
| 帆布袋 | 275.00 |
| 台灯 | 0.00 |
ORDER BY 可以用这个别名。中性笔和水杯都是 480.00,再按 id 排,顺序才定得下来。别名习惯用英文小写,几个词之间用下划线,不要有空格。
可是 WHERE 里用不了别名:
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(数, 位数) 四舍五入到几位小数;不写位数就是到整数:
1SELECT name, price, ROUND(price), ROUND(price * 0.85, 2) AS sale_price2FROM products3WHERE price > 20;
| name | price | ROUND(price) | sale_price |
|---|---|---|---|
| 双肩包 | 39.90 | 40 | 33.92 |
| 耳机 | 59.00 | 59 | 50.15 |
| 台灯 | 25.00 | 25 | 21.25 |
ROUND 这样的东西叫函数:名字后面跟括号,括号里是要处理的值,用逗号隔开。
文字函数
处理文字常用的几个:CONCAT 把几段文字接起来,UPPER 把英文字母变大写,LENGTH 算长度:
1SELECT CONCAT(name, '(', city, ')') AS who, UPPER(email) AS email2FROM customers3WHERE id <= 3;
| who | |
|---|---|
| 林晓(上海) | [email protected] |
| 王磊(北京) | [email protected] |
| 陈静(上海) | NULL |
陈静没有邮箱,UPPER(NULL) 还是 NULL。CONCAT 也一样,接上一个 NULL,整个结果就是 NULL。别的数据库常用 || 接文字(name || city),MySQL 里 || 默认是「或」的意思,所以这里用 CONCAT。
数长度要小心:LENGTH 数的是字节,一个汉字占 3 个字节;数字数要用 CHAR_LENGTH:
1SELECT name, LENGTH(name), CHAR_LENGTH(name)2FROM products3WHERE category = '厨房';
| name | LENGTH(name) | CHAR_LENGTH(name) |
|---|---|---|
| 水杯 | 6 | 2 |
| 咖啡杯 | 9 | 3 |
CASE:按条件给不同的值
CASE 像一串「如果……就……」:从上往下看每个 WHEN,第一个成立的,用它的 THEN 后面的值;都不成立,用 ELSE 的值。最后写 END。按库存给商品标个状态:
1SELECT name, stock,2 CASE3 WHEN stock = 0 THEN '缺货'4 WHEN stock < 20 THEN '快卖完了'5 ELSE '有货'6 END AS stock_status7FROM products;
| name | stock | stock_status |
|---|---|---|
| 笔记本 | 120 | 有货 |
| 中性笔(10 支) | 80 | 有货 |
| 双肩包 | 15 | 快卖完了 |
| 水杯 | 40 | 有货 |
| 耳机 | 10 | 快卖完了 |
| 台灯 | 0 | 缺货 |
| 数据线 | 200 | 有货 |
| 咖啡杯 | 60 | 有货 |
| 手机壳 | 35 | 有货 |
| 帆布袋 | 25 | 有货 |
15 元的手机壳,label 是什么?
1SELECT name,2 CASE3 WHEN price < 50 THEN '便宜'4 WHEN price < 20 THEN '很便宜'5 ELSE '贵'6 END AS label7FROM products8WHERE price = 15;
CASE 用第一个成立的 WHEN。15 小于 50,第一个就成立了,后面的 WHEN price < 20 根本不看。所以条件要从严到宽写:先写 < 20,再写 < 50。
别漏了最后的 END:漏了它,MySQL 读到 AS 还在等 END,就会报语法错误 ERROR 1064。
练一练
写好查询,点检查。提示随便看,实在想不出来再看答案。
库存值多少钱
✓查出数码类商品的 name 和库存总值 stock_value(价格乘库存)两列,按 id 排。
| name | stock_value |
|---|---|
| 耳机 | 590.00 |
| 台灯 | 0.00 |
| 数据线 | 1700.00 |
| 手机壳 | 525.00 |
1SELECT name, price, stock2FROM products3WHERE category = '数码';
打八五折
✓箱包类商品打八五折。显示 name、price 和 sale_price 三列,sale_price 四舍五入到 2 位小数,按 id 排。
| name | price | sale_price |
|---|---|---|
| 双肩包 | 39.90 | 33.92 |
| 帆布袋 | 11.00 | 9.35 |
1SELECT name, price2FROM products3WHERE category = '箱包';
价格档次
✓给每件商品标档次,显示 name、price、price_level 三列:低于 10 的是 便宜,10 到 30 之间(不到 30)的是 中等,其余是 贵,按 id 排。
| name | price | price_level |
|---|---|---|
| 笔记本 | 4.50 | 便宜 |
| 中性笔(10 支) | 6.00 | 便宜 |
| 双肩包 | 39.90 | 贵 |
| 水杯 | 12.00 | 中等 |
| 耳机 | 59.00 | 贵 |
| 台灯 | 25.00 | 中等 |
| 数据线 | 8.50 | 便宜 |
| 咖啡杯 | 9.90 | 便宜 |
| 手机壳 | 15.00 | 中等 |
| 帆布袋 | 11.00 | 中等 |
1SELECT name, price2FROM products;
这一课学会了
SELECT里可以写算式,每一行算一遍;表里的数据不变。AS 名字给列起别名,ORDER BY里可以用它,WHERE里不行。ROUND(数, 位数)四舍五入;CONCAT接文字,UPPER变大写,LENGTH数字节、CHAR_LENGTH数字数。- 函数碰到
NULL,结果通常也是NULL。 CASE WHEN … THEN … ELSE … END用第一个成立的WHEN,别漏了END。