今回はPostgreSQLのLIMITとOFFSETを使い、取得する行数と読み飛ばす行数を指定する方法を整理します。
所要時間は15分ほどです。
それでは、さっそく始めていきましょう!
今日のテーマと到達目標
価格順に並べた商品から指定した件数を取得し、取得結果の制限と元のデータの削除を区別することが目標です。
用語の定義
| 用語 | 意味 |
|---|---|
| LIMIT | 結果として返す行数の上限を指定する |
| OFFSET | 結果の先頭から読み飛ばす行数を指定する |
| ORDER BY | 結果の行を並べる基準と方向を指定する |
| ASC | 昇順。今回の価格では安い順 |
| 結果セット | SELECTの実行で返される行と列の集まり |
今回使用するTableはproductsです。1行は商品1種類を表し、product_idは商品を識別する番号、product_nameは商品名、price_yenは円単位の価格です。
登録済みの商品は次の3件です。
| product_id | product_name | price_yen |
|---|---|---|
| 1 | onigiri | 100 |
| 2 | bento | 500 |
| 3 | ame | 50 |
LIMITとOFFSETの関係
SELECT product_name, price_yen
FROM products
ORDER BY price_yen ASC
LIMIT 2 OFFSET 1;
この指定は、結果を考える際に次の順で整理できます。
- 価格の安い順に並べる。
- 先頭の1行を読み飛ばす。
- 残った行から最大2行を返す。
これは結果の意味を説明したもので、データベース内部の処理手順を示すものではありません。
OFFSET 1の1は読み飛ばす行数です。商品IDが1の商品を除外する指定ではありません。
LIMITで最大2行を取得する
まず、次のSQLを実行しました。
SELECT product_name, price_yen
FROM products
ORDER BY price_yen ASC
LIMIT 2;
実行結果は次のとおりです。
product_name | price_yen
--------------+-----------
ame | 50
onigiri | 100
(2 行)
価格が安い順に、先頭の2行を取得できました。bentoは今回の結果に含まれませんが、元のTableから削除されたわけではありません。
OFFSETで先頭の1行を読み飛ばす
次はOFFSET 1を追加します。
SELECT product_name, price_yen
FROM products
ORDER BY price_yen ASC
LIMIT 2 OFFSET 1;
実行前に「onigiri → bentoの順」と予想しました。実際の結果も予想どおりでした。
product_name | price_yen
--------------+-----------
onigiri | 100
bento | 500
(2 行)
先頭のameを読み飛ばした後の2行が返されています。
LIMITは必ずその行数を返すのか
最後に、同じ価格の昇順でLIMIT 2 OFFSET 2を指定したら何が返るかを考えました。
回答は「bentoが1行」です。
3行のうち先頭の2行を読み飛ばすと、残るのはbentoの1行だけです。LIMIT 2は最大2行という意味なので、残りが1行なら1行だけ返ります。
この条件は確認問題への回答として確認したもので、今回共有した実行画面には含まれていません。
読み飛ばした商品は削除されるのか
「OFFSETで読み飛ばした商品は、元のproductsから削除されるか」という質問には、「されていない」と回答しました。
SELECTに指定するLIMITとOFFSETは、返す結果の範囲を決めます。元のTableに記録された商品を削除する操作ではありません。
行の順番を指定する理由
ORDER BYがないSELECTでは、返される行の順序は保証されません。どの行を読み飛ばし、どの行を取得するかを決めたい場合は、並び順も指定します。
今回の3商品は価格がすべて異なるため、価格だけで順序が決まります。同じ価格の商品がある場合は、その商品の間の順序まで決まるように、並べ替えの基準を追加する必要があります。
合格条件と学習記録
| 確認項目 | 確認できた内容 |
|---|---|
| 取得行数を制限できる | LIMIT 2でameとonigiriの2行を取得 |
| 先頭の行を読み飛ばせる | OFFSET 1でonigiri、bentoの順になると予想し、実行結果も一致 |
| 行数の上限を理解している | LIMIT 2 OFFSET 2ではbentoが1行と回答 |
| 元データの削除と区別できる | 読み飛ばした商品は削除されないと回答 |
共有した2つのSQLはエラーなく実行でき、確認問題にも正しく回答できました。
まとめ
| 指定 | 意味 |
|---|---|
| LIMIT 2 | 最大2行を返す |
| OFFSET 1 | 先頭の1行を読み飛ばす |
| LIMIT 2 OFFSET 1 | 先頭の1行を読み飛ばして、最大2行を返す |
LIMITは返す行数の上限、OFFSETは読み飛ばす行数です。どちらも、元のTableの行を削除する指定ではありません。