-- 好的縮進
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);