SQL実践入門 ──高速でわかりやすいクエリの書き方

サポートページ

この記事を読むのに必要な時間:およそ 0.5 分

ダウンロード

本書で使用するサンプルコードはダウンロードできます。圧縮ファイルをダウンロードしていただき,適宜解凍してご利用ください。

ダウンロード
サンプルコード

お詫びと訂正(正誤表)

本書の以下の部分に誤りがありました。ここに訂正するとともに,ご迷惑をおかけしたことを深くお詫び申し上げます。

(2016年9月5日更新)

初版第1刷をお持ちの方(第2刷で修正済み)

P.229 リスト8.7

studdent_id
student_id

P.283 リスト9.20 10行目

INSERT INTO OrderReceipts VALUES (10000, 3, '牛肉',  2011/8/26');
INSERT INTO OrderReceipts VALUES (10000, 3, '牛肉', '2011/8/26');

P.316 リスト10.18

CREATE INDEX CoveringIndex_2 ON Orders (receive_shop, order_id, receive_date);
CREATE INDEX CoveringIndex_2 ON Orders (shop_name, order_id, receive_date);

P.318 図b

物理的には行単位でひとまとまり
物理的には単位でひとまとまり

P.338 リストB.2

INSERT INTO Sales2
SELECT company,
        year,
        sale,
        CASE SIGN(sale - (SELECT MAX(sale)  --  直前のレコードと売り上げを比較
                            FROM Sales SL2
                           WHERE SL1.company = SL2.company
                             AND SL1.year > SL2.year ))
        WHEN 0  THEN '='
        WHEN 1  THEN '+'
        WHEN -1 THEN '-'
        ELSE NULL END AS var
   FROM Sales SL1;
INSERT INTO Sales2
SELECT company,
        year,
        sale,
        CASE SIGN(sale - (SELECT sale -- 直近の年の売り上げを選択
                            FROM Sales SL2
                           WHERE SL1.company = SL2.company
                             AND SL2.year =
                               (SELECT MAX(year)  -- 直近の年を選択
                                  FROM Sales SL3
                                 WHERE SL1.company = SL3.company
                                   AND SL1.year > SL3.year )))
        WHEN 0  THEN '='
        WHEN 1  THEN '+'
        WHEN -1 THEN '-'
        ELSE NULL END AS var
   FROM Sales SL1;

P.338 図B.8

--------------------------------------------------------------------------------------------
| Id  | Operation                    | Name        | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |             |    12 |   108 |3   (0)     | 00:00:01 |
|   1 |  SORT AGGREGATE              |             |     1 |     9 |            |          |
|   2 |   TABLE ACCESS BY INDEX ROWID| SALES       |     1 |     9 |2   (0)     | 00:00:01 |
|*  3 |    INDEX RANGE SCAN          | SYS_C004248 |     1 |       |1   (0)     | 00:00:01 |
|   4 |  TABLE ACCESS FULL           | SALES       |    12 |   108 |3   (0)     | 00:00:01 |
--------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------
| Id  | Operation                       | Name     | Rows  | Bytes | Cost  (%CPU)| Time     |
--------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                |          |    12 |   108 |2   (0)      | 00:00:01 |
|   1 |  SORT AGGREGATE                 |          |     1 |     9 |             |          |
|   2 |   TABLE ACCESS BY INDEX ROWID   | SALES    |     1 |     9 |1   (0)      | 00:00:01 |
|*  3 |    INDEX UNIQUE SCAN            | PK_SALES |     1 |       |0   (0)      | 00:00:01 |
|   4 |     SORT AGGREGATE              |          |     1 |     6 |             |          |
|   5 |      FIRST ROW                  |          |     1 |     6 |1   (0)      | 00:00:01 |
|*  6 |       INDEX RANGE SCAN (MIN/MAX)| PK_SALES |     1 |     6 |1   (0)      | 00:00:01 |
|   7 |  TABLE ACCESS FULL              | SALES    |    12 |   108 |2   (0)      | 00:00:01 |
--------------------------------------------------------------------------------------------

P.338-339 「演習問題5の解答」3段落目

相関サブクエリではSL1.company = SL2.companyという条件によって「同じ会社ならば」という条件を実現できるため、CASE式による条件分岐が1つ減ります。こちらは、典型的なSQLの集合指向の考え方です。相関サブクエリの中で非等値結合を使うことによってカレントレコードを起点とした集合を作るのは、ウィンドウ関数が導入される前のSQLでは定石の技術でした。

今、相関サブクエリの中では、SL3テーブルからMAX(year)を選択することであるレコードの直近の前年を取得し、これと同じ年のsale列をSL2から選択しています。これがすなわち「直近の年の売り上げ」になります。その条件の中心となるのが、SL1.year > SL2.yearという不等式です。カレントレコードはSL1.yearのほうですから、「それより小さい(=昔の)年」という意味になります。

SL1.yearと、SL1.year > SL2.yearの条件に合致するレコード集合の対応をマッピングすると図B.9のようになります(太字の年は、集合の中の最大値を示します)。

相関サブクエリではSL1.company = SL2.company(およびSL1.company = SL3.company)という条件によって「同じ会社ならば」という条件を表現します。こちらは、典型的なSQLの集合指向の考え方です。相関サブクエリの中で非等値結合を使うことによってカレントレコードを起点とした集合を作るのは、ウィンドウ関数が導入される前のSQLでは定石の技術でした。

今、相関サブクエリの中では、同じ会社で、カレント行の年より前で直近の年MAX(year)をSL3テーブルから選択しています。この年における売り上げが、すなわちカレント行に対する「直近の年の売り上げ」になります。その条件の中心となるのが、SL1.year > SL3.yearという不等式です。カレントレコードはSL1.yearのほうですから、「それより小さい(=昔の)年」という意味になります。

SL1.yearと、SL1.year > SL3.yearの条件に合致するレコード集合の対応をマッピングすると図B.9のようになります(太字の年は、集合の中の最大値を示します)。

P.339 図B.9

SL1.year > SL2.yearの条件に該当するレコード集合
SL1.year > SL3.yearの条件に該当するレコード集合

初版第1~2刷をお持ちの方
P.87

図3.11 UNIONの実行計画(PostgreSQL)
図3.11 CASE式の実行計画(PostgreSQL)

P.93 「UNIONを使ったほうがパフォーマンスが良いケース」(P.92)の4段落3行目

図3.12のサンプルデータ
図3.16のサンプルデータ

P.94 注8

このサンプルにように
このサンプルように

初版第1~2刷をお持ちの方

P.218 リスト7.9

SELECT C.co_cd, C.district,
SELECT C.co_cd, MAX(C.district),