前面學了 ORDER BY 排序,接下來要學一個常常跟排序搭配使用的指令:LIMIT(限制筆數)。
當資料量很大的時候,你可能只想看前幾筆,或是做分頁顯示,這時候就需要用到 LIMIT。
什麼是 LIMIT 和 OFFSET?
假設老闆說:「資料好多,不想看,你幫我挑出 10 個會員就好。」
你聽到這個要求,應該會問:
- 要挑幾筆?(數量)
- 從第幾筆開始?(起點)
換個方式說:
- LIMIT:我要取幾筆資料
- OFFSET:我要跳過幾筆資料
知道「跳過幾筆」和「取幾筆」,你就知道要取第幾筆到第幾筆了。
LIMIT 和 OFFSET 的基本語法
LIMIT 數量
LIMIT 數量 OFFSET 跳過的筆數舉個例子:
-- 取前 5 筆
LIMIT 5
-- 取第 6 到第 10 筆(跳過前 5 筆,取 5 筆)
LIMIT 5 OFFSET 5OFFSET 是「跳過幾筆」,不是「從第幾筆開始」
這點很容易搞混。
假設你要取第 6 到第 10 筆(共 5 筆):
| 要取的資料 | LIMIT | OFFSET |
|---|---|---|
| 第 6 到第 10 筆 | 5 | 5 |
為什麼 OFFSET 是 5?
因為你要跳過前 5 筆(第 1 到第 5 筆),從第 6 筆開始取。
通常只需要寫 LIMIT
大部分情況下,你只需要取「前幾筆」資料。
這時候不用寫 OFFSET,因為預設就是從第 1 筆開始(跳過 0 筆)。
-- 取前 10 筆,不用寫 OFFSET
LIMIT 10找出年紀最小的三個會員
老闆說:「請你幫我找出年紀最小的三個會員。」
「最小的三個」是什麼意思?
就是:
- 先按照年紀從小到大排序
- 取前三筆
SELECT *
FROM 會員
ORDER BY 年紀 ASC
LIMIT 3因為是從小排到大(ASC 是預設值),所以前三筆就是年紀最小的三個人。
不用寫 OFFSET,因為是從第 1 筆開始取。
邊界值相同時怎麼辦?
如果最小的五個會員年紀分別是 1、1、2、2、2 歲,你取前三個會怎樣?
| 排名 | 年紀 |
|---|---|
| 1 | 1 |
| 2 | 1 |
| 3 | 2 |
| 4 | 2 |
| 5 | 2 |
你會取到第 1、2、3 名,但第 3、4、5 名年紀都是 2 歲。
這樣切在第 3 筆,其實有點不公平,因為同樣是 2 歲,為什麼第 3 名入選,第 4、5 名沒有?
這個問題需要用到 RANK(排名)的概念來處理,但那是比較進階的內容,之後再介紹。
目前先知道:單純用 LIMIT 切資料,可能會遇到邊界值相同的問題。
用 SQL 隨機抽獎
老闆說:「我們要抽獎,請你隨機挑出五名會員。」
怎麼做到「隨機」?
兩種抽獎的思路
想像一下,如果在真實生活中,你要隨機抽五個人,可以怎麼做?
方法一:骰五次骰子
大家先排隊站好,然後骰五次骰子,骰到的號碼就得獎。
比如說骰出 3、17、29、8、42,那排在第 3、17、29、8、42 位的人就得獎。
方法二:每人骰一次
每個人都骰一個骰子,然後按照骰出的數字排序,取前五名。
為什麼要用每人骰一次的方式?
方法一在目前學的指令中做不到。
為什麼?
假設你要知道「小明排在第幾位」,你要怎麼知道?
你必須數:小明前面有幾個人。
如果小明前面有 5 個人,小明就是第 6 位。
但問題是:目前學的指令,每筆資料都是「獨立處理」的。
什麼意思?
回想一下前面學的 SELECT:
SELECT 名稱, 單價 * 1.05 AS 含稅價
FROM 商品當資料庫在計算「蘋果」的含稅價時,它只看蘋果自己的單價,不需要知道香蕉、牛奶的單價是多少。
每筆資料的計算都是獨立的,不用參考其他筆資料。
但是「小明排在第幾位」這件事就不一樣了。
你沒辦法只看小明自己的資料就算出他是第幾位,你必須知道「其他人」的資訊——小明前面有幾個人。
這種「需要參考其他筆資料」的計算,目前學的指令還做不到。
這就是為什麼方法一做不到——你需要「數其他人」才能知道自己是第幾位。
方法二就不一樣了。
每個人骰骰子、得到一個隨機數,這件事情不需要看別人。
小明骰出 42,這跟其他人骰出多少完全無關。
所以方法二可以做到。
用 RANDOM() 實作隨機抽獎
SELECT *, RANDOM() AS 幸運值
FROM 會員
ORDER BY 幸運值
LIMIT 5RANDOM() 是一個函數,會產生一個隨機的數字。
每次執行這個查詢,每筆資料的「幸運值」都會不一樣,排序結果也會不一樣。
所以每次抽出的五個人都會不同,達到「隨機抽獎」的效果。
為什麼可以在 ORDER BY 用 SELECT 定義的別名?
注意看這個查詢:
SELECT *, RANDOM() AS 幸運值
FROM 會員
ORDER BY 幸運值
LIMIT 5「幸運值」是在 SELECT 裡面定義的別名,但我們在 ORDER BY 裡面用了它。
這樣可以嗎?
可以!
因為 ORDER BY 在 SELECT 之後執行,這時候「幸運值」這個欄位已經算出來了。
這就是為什麼一直強調執行順序很重要:
| 順序 | 指令 |
|---|---|
| 1 | FROM |
| 2 | WHERE |
| 3 | SELECT |
| 4 | ORDER BY |
| 5 | LIMIT |
理解執行順序,你就知道哪些別名可以用、哪些不行。
小結
這篇文章介紹了 LIMIT 和 OFFSET:
- LIMIT:限制取出的筆數
- OFFSET:跳過幾筆資料(不是從第幾筆開始)
- 排序 + 限制:可以找出「最大的 N 個」或「最小的 N 個」
- 隨機抽獎:用 RANDOM() 產生隨機數,排序後取前 N 筆
- 執行順序:LIMIT 在最後執行,ORDER BY 在 SELECT 之後
排序加上數量限制,就能實現很多實用的功能,像是排行榜、分頁、抽獎等等。