-- 好的缩进
SELECT col_1,
col_2,
col_3,
COUNT(*)
FROM tbl_A
WHERE col_1 = 'a'
AND col_2 = ( SELECT MAX(col_2)
FROM tbl_B
WHERE col_3 = 100 )
GROUP BY col_1,
col_2,
col_3-- 坏的示例 SELECT col1_1, col_2, col_3, COUNT(*) FROM tbl_A WHERE col1_1 = 'a' AND col1_2 = ( SELECT MAX(col_2) FROM tbl_B WHERE col_3 = 100 ) GROUP BY col_1, col_2, col_3
-- 好的示例
SELECT col_1
FROM tbl_A A, tbl_B B
WHERE ( A.col_1 >= 100 OR A.col_2 IN ( 'a', 'b' ) )
AND A.col_3 = B.col_3;-- 坏的示例 SELECT col_1 FROM tbl_A A,tbl_B B WHERE (A.col_1>=100 OR A.col_2 IN ('a','b')) AND A.col_3=B.col_3;
四、大小写
关键字使用大小写,表名列名使用小写,以下
SELECT col_1, col_2, col_3,
COUNT(*)
FROM tbl_A
WHERE col_1 = 'a'
AND col_2 = ( SELECT MAX(col_2)
FROM tbl_B
WHERE col_3 = 100 )
GROUP BY col_1, col_2, col_3
来看看如何巧用 CASE WHEN 进行定制化统计,假设咱们有以下的需求,但愿根据左边各个市的人口统计每一个省的人口
使用 CASE WHEN 以下
SELECT CASE pref_name
WHEN '长沙' THEN '湖南'
WHEN '衡阳' THEN '湖南'
WHEN '海口' THEN '海南'
WHEN '三亚' THEN '海南'
ELSE '其余' END AS district,
SUM(population)
FROM PopTbl
GROUP BY district;
2、巧用 CASE WHEN 进行更新
如今某公司员人工资信息表以下:
如今公司出台了一个奇葩的规定
对当前工资为 1 万以上的员工,降薪 10%。
对当前工资低于 1 万的员工,加薪 20%。
一些人不假思索可能写出了如下的 SQL:
--条件1
UPDATE Salaries
SET salary = salary * 0.9 WHERE salary >= 10000;
--条件2
UPDATE Salaries
SET salary = salary * 1.2
WHERE salary < 10000;
DELETE FROM Products P1
WHERE id < ( SELECT MAX(P2.id)
FROM Products P2
WHERE P1.name = P2.name
AND P1.price = P2.price );
二、排序
在 db 中,咱们常常须要按分数,人数,销售额等进行排名,有 Oracle, DB2 中可使用 RANK 函数进行排名,不过在 MySQL 中 RANK 函数未实现,这种状况咱们可使用自链接来实现,如对如下 Products 表按价格高低进行排名
使用自链接能够这么写:
-- 排序从 1 开始。若是已出现相同位次,则跳过以后的位次
SELECT P1.name,
P1.price,
(SELECT COUNT(P2.price)
FROM Products P2
WHERE P2.price > P1.price) + 1 AS rank_1
FROM Products P1
ORDER BY rank_1;
此函数做用返回参数中的第一个非空表达式,假设有以下商品,咱们从新格式化同样,若是 city 为 null,表明商品不在此城市发行,但咱们在展现结果的时候不想展现 null,而想展现 'N/A', 能够这么作:
SELECT
COALESCE(city, 'N/A')
FROM
customers;
SQL 性能优化技巧
1、参数是子查询时,使用 EXISTS 代替 IN
若是 IN 的参数是(1,2,3)这样的值列表时,没啥问题,但若是参数是子查询时,就须要注意了。好比,如今有以下两个表:
如今咱们要查出同时存在于两个表的员工,即田中和铃木,则如下用 IN 和 EXISTS 返回的结果是同样,可是用 EXISTS 的 SQL 会更快:
-- 慢
SELECT *
FROM Class_A
WHERE id IN (SELECT id
FROM CLASS_B);
-- 快
SELECT *
FROM Class_A A
WHERE EXISTS
(SELECT *
FROM Class_B B
WHERE A.id = B.id);
-- 聚合后使用 HAVING 子句过滤
SELECT sale_date, SUM(quantity)
FROM SalesHistory GROUP BY sale_date
HAVING sale_date = '2007-10-01';
-- 聚合前使用 WHERE 子句过滤
SELECT sale_date, SUM(quantity)
FROM SalesHistory
WHERE sale_date = '2007-10-01'
GROUP BY sale_date;
使用第二条语句效率更高,缘由主要有两点
使用 GROUP BY 子句进行聚合时会进行排序,若是事先经过 WHERE 子句能筛选出一部分行,能减轻排序的负担
在 WHERE 子句中可使用索引,而 HAVING 子句是针对聚合后生成的视频进行筛选的,但不少时候聚合后生成的视图并无保留原表的索引结构
5、在 GROUP BY 子句和 ORDER BY 子句中使用索引
GROUP BY 子句和 ORDER BY 子句通常都会进行排序,以对行进行排列和替换,不过若是指定带有索引的列做为这二者的参数列,因为用到了索引,能够实现高速查询,因为索引是有序的,排序自己都会被省略掉
6、使用索引时,条件表达式的左侧应该是原始字段
假设咱们在 col 列上创建了索引,则下面这些 SQL 语句没法用到索引
SELECT *
FROM SomeTable
WHERE col * 1.1 > 100;
SELECT *
FROM SomeTable
WHERE SUBSTR(col, 1, 1) = 'a';
SELECT *
FROM SomeTable
WHERE col_1 > 100 or col_1 < 100;
8、进行默认的类型转换
假设 col 是 char 类型,则推荐使用如下第二,三条 SQL 的写法,不推荐第一条 SQL 的写法
× SELECT * FROM SomeTable WHERE col_1 = 10;
○ SELECT * FROM SomeTable WHERE col_1 = '10';
○ SELECT * FROM SomeTable WHERE col_1 = CAST(10, AS CHAR(2));
这一点与上面第八条相呼应,对聚合结果指定筛选条件时,使用 HAVING 是基本的原则,可能一些工程师会倾向于使用下面这样的写法:
SELECT *
FROM (SELECT sale_date, MAX(quantity) AS max_qty
FROM SalesHistory
GROUP BY sale_date) TMP
WHERE max_qty >= 10;
虽然上面这样的写法能达到目的,但会生成 TMP 这张临时表,因此应该使用下面这样的写法:
SELECT sale_date, MAX(quantity)
FROM SalesHistory
GROUP BY sale_date
HAVING MAX(quantity) >= 10;
HAVING 子句和聚合操做是同时执行的,因此比起生成中间表后再执行 HAVING 子句,效率会更高,代码也更简洁
十、须要对多个字段使用 IN 谓词时,将它们汇总到一处
一个表的多个字段可能都使用了 IN 谓词,以下:
SELECT id, state, city
FROM Addresses1 A1
WHERE state IN (SELECT state
FROM Addresses2 A2
WHERE A1.id = A2.id)
AND city IN (SELECT city
FROM Addresses2 A2
WHERE A1.id = A2.id);
这段代码用到了两个子查询,也就产生了两个中间表,能够像下面这样写
SELECT *
FROM Addresses1 A1
WHERE id || state || city
IN (SELECT id || state|| city
FROM Addresses2 A2);