しぐまろぐ

勉強したことや読んだ本について書きます。

ミック『SQL ゼロからはじめるデータベース操作[第2版]』

本書を読んで知ったこと、気を付けたいことの個人的なメモ
構文はMySQLで記載

第1章 データベースとSQL

文字列の記述(p28)

文字列、日付をSQL文の中に記述する場合は、シングルクォーテーションで囲む

テーブル名の訂正(p41)

標準SQLは存在しないが、各データベースでコマンドが存在する

rename table [変更前テーブル名] to [変更後テーブル名];

第2章 検索の基本

列に別名をつける(p48)

別名に日本語を使う場合は、列名をダブルクォーテーションで囲む

select [カラム名] as “[別名]” from [テーブル名];

ex) select id as “商品ID”, shiire_tanka as “仕入単価” from Shohin;

結果から重複行を省く(p50)

※DISTINCTキーワードは先頭の列名の前にしか置けない

WHERE句による行の選択(p52)

WHERE句で指定した条件に合う行をまず選択し、その後にSELECT句で指定した列を出力する。
※SELECTよりもWHEREが先に実行されるため、SELECT文で指定ついた別名をWHERE句で用いるとエラーになる。

コメントの書き方(p55)

MySQLでは、「--」の後に半角スペースを入れないとコメントとみなされない。
※コメントは、SQLの途中に差し込むことができる。

SQL途中にコメント入れてエラーになったことがあったので、SQL途中にはコメントを入れられないと思っていたけど、あのときエラーになったのは「--」の後に半角スペースがなかったせいだろう。

NULLには要注意(p58)

NULLを含んだ計算は、問答無用でNULLになる。
ex) NULL + 5 → NULL,

ex2) 4 / NULL → NULL

NULLを含んだ列の計算を行いたい場合は、coalesce(コアレス)関数を使う(後述)。

NULLを含む場合の真理値

「shiire_tanka = 2800」という条件式に照らしたとき、shiire_tankaがNULLの行の真理値は、真でも偽でもなく、「不明(UNKNOWN)」になる。
普通の論理演算には「不明」は存在しない。通常の論理演算が2値論理と呼ばれるのに対し、SQLは3値論理と呼ばれる。

第3章 集約と並べ替え

NULLを除外して行数を数える(p83)

ある列のNULL行を除外して行数を数えたい場合

select count([対象カラム列名]) from [テーブル名];

合計を求める(p84)

四則演算にNULLが含まれる場合、結果は問答無用でNULLになるはず(前述)だが、対象列にNULLがあっても合計値はNULLにならない。すべての集約関数は、列名を引数に取った場合、計算前にNULLを除外するため。

group by/where句を併用するときのselect文の実行順序(p95)

from → where → group by → select

集約関数とgroup by句にまつわるよくある間違い(p96)

  • よくある間違い① select句に余計な列を書いてしまう

select句に書けるのは、下記3つのみ。
1.定数
2.集約関数
3.group by句で指定した列名(集約キー)

  • よくある間違い② group by句に列の別名を書いてしまう

group by句がselect句より前に実行されるため、エラーになる。

having句よりもwhere句に書いた方がいい条件(p105)

集約キーに対する条件は、having句にもwhere句にも書けるが、どちらに書いた方がいいのか。
下記のようにどちらでも書ける。

-- having句で制限
select shohin_bunrui, count(*)
from shohin
group by shohin_bunrui
having shohin_bunrui = '衣服';

-- where句で制限
select shohin_bunrui, count(*)
from shohin
where shohin_bunrui = '衣服';
group by shohin_bunrui;

where句とhaving句の役割の違いで考える。
where句は行に対する条件指定
having句はグループに対する条件指定
→行に対する条件指定はwhere句に書くべき。

?このとき、すでにwhere句でshohin_bunruiを1つに絞っているから、group byは必要ないのでは?

NULLの順番(p110)

NULLに比較演算子は使えないため、NULLを含む列をソートキー(order by句に書く列名)にした場合、NULLは先頭または末尾にまとめて表示される。

ソートキーに表示用の別名を使う(p111)

group by句にはselect句でつけた列の別名は使用できないが、order by句では使用できる。
これは、DBMS内部でSQLが実行される順番が下記の通りのため。※selectの位置に注目
from → where → group by → having → select → order by

order by句に使える列

order by句には、テーブルに存在する列または集約関数が使える。select句に含まれているかどうかは無関係。

第4章 データの更新

デフォルト値を挿入する(p124)

テーブルの列には、デフォルト値(初期値)を設定することができる。
create table文の中で、列に対してDEFAULT制約を付加すればよい。
テーブル定義にデフォルト値が設定されていた場合、自動的にそれをinsert文の列の値として使用できる。
方法は、明示的な方法、暗黙的な方法の2通りがある。
明示的な方法には、hanbai_tankaにdefault値が設定されていることが一目見てわかるという利点がある。

  • 明示的な方法

ex) hanbai_tankaにdefault 0が設定されている。

insert into ShohinIns
(shohin_id, shohin_mei, shohin_bunrui, hanbai_tanka, shiire_tanka, torokubi)
values
(‘007’, ‘おろしがね’, ‘キッチン用品’, default, 790, ‘2009-04-28’); 
  • 暗黙的な方法

ex) hanbai_tankaにdefault 0が設定されているので、列リストからもvaluesからも省く。

insert into ShohinIns
(shohin_id, shohin_mei, shohin_bunrui, shiire_tanka, torokubi)
values
(‘007’, ‘おろしがね’, ‘キッチン用品’,790, ‘2009-04-28’); 

delete文の基本構文(p129)

基本構文は下記の通り。

delete from [テーブル名];

「delete [テーブル名]」や「delete [列名] from [テーブル名]」などと書きがちだが、削除対象となるのがテーブルや列ではなく、あくまで「行(レコード)」であることを考えれば、納得して覚えられるはず。

削除と切り捨て(p132)

多くのデータベースには「truncate(トランケート)」という全行削除用のコマンドがある。細かい制御ができない代わりに処理が高速。
※ただし、Oracleのように、truncateをDDLとして定義している(つまりロールバックできない)データベースもあるため、注意。

トランザクションを作るには(p142)
標準SQL規格でトランザクションが暗黙に開始されると決まっているため、DBMSによって「トランザクション開始文」はバラバラ。

トランザクションはいつはじまるのか(p144)

暗黙的にトランザクションが開始される場合、そのトランザクションの区切りはどうなるのか。下記2つのパターンがあり、どちらのモードも選択可能である。


1.「1つのSQLで1つのトランザクション」というルールが適用される(自動コミットモード)

2. ユーザーがCOMMITまたはROLLBACKを実行するまでが1つのトランザクションとみなされる

第5章 複雑な問い合わせ

ビューとテーブル(p151)

違いはただ1つ、「実際のデータを保存しているか否か」。テーブルにはデータが保存できるが、ビューはデータを保存していない。ビューが保存しているのはselect文だけ。ビューを実行すればselect文が実行されるため、最新のデータを参照できる。

ビューの制限事項① ビュー定義でorder by句は使えない。(p156)

理由は、テーブルと同様、ビューについても「行には順番がない」と定められているから。

ビューの制限事項② ビューに対する更新(p157)

ビューでの変更を元のテーブルにどう反映するか判断できる場合のみ、ビューを更新できる。

サブクエリとビュー(p162)

サブクエリは、「使い捨てのビュー」。ビュー定義のselect文をそのままfrom句に持ち込んでしまったもの。内側のselect文から実行される。

select shohin_bunrui, cnt_shohin
from (select shohin_bunrui, count(*) as cnt_shohin
         from Shohin
         group by shohin_bunrui) as ShohinSum;

スカラ・サブクエリ(p165)

「必ず1行1列だけの戻り値を返す」という制限をつけたサブクエリのこと。

select shohin_id, shohin_mei, hanbai_tanka
from Shohin
where hanbai_tanka > (select avg(hanbai_tanka) from Shohin);

普通のサブクエリと相関サブクエリの違い(p170)

相関サブクエリは、小分けにしたグループ内での比較をするときに使う。

ex) 商品分類ごとに平均販売単価より高い商品を、商品分類のグループから選び出す。

select shohin_bunrui,shohin_mei,hanbai_tanka
from shohin t1
where hanbai_tanka >
(select avg(hanbai_tanka)
from shohin t2
where t1.shohin_bunrui = t2.shohin_bunrui
group by shohin_bunrui);

サブクエリ内のwhere句の条件がポイント。これで、外側に対して1行しか返さなくなる。
「各商品の販売単価と平均販売単価の比較を、同じ商品分類の中で行う」という意味。

第6章 関数、述語、CASE式

|| 連結(p186)

文字列連結には、「||」という関数を使う。

ex)
select str1, str2, str1 || str2 from sample;


ただし、MySQLでは使用できないため、concat(コンキャット)関数を使う。
ex)

select str1, str2, concat(str1, str2) from sample;

coalesce関数(p198)

coalesce関数は、可変個の引数を鳥、左から順に引数を見て、NULLでない最初の値を返す。
ex) select coalesce(null, null, “test”, 1)の場合、testを返す

ex2)
select 5 + coalesce(null, null, 1);
6となる。

述語とは(p200)

「戻り値が真理値になる」という特別な条件を満たす関数のこと。

練習問題解説(p311)

not inの引数にNULLが含まれている場合、常に結果は空になってしまう。
理由については、『達人に学ぶSQL徹底指南書』の「第1部:1-3 3値論理とNULL」を参照とのこと。

exist述語(p212)

existは、引数を1つだけ右側に取り、そしてその引数は必ず相関サブクエリ。

第7章 集合演算

集合演算とは(p225)
集合演算とは、レコード同士を足したり引いたりする、いわばレコードの「四則演算」である。
集合演算子は、通常は重複行が排除される。(all オプションをつければ、重複行を残せる)

集合演算の注意事項(p227)

・演算対象となるレコードの列数は同じであること
・足し算の対象となるレコードの列のデータ型が一致していること
・select文はどんなものを指定しても良いが、order by句は最後に1つだけ

テーブルの共通部分の選択 INTERSECT(p230)

レコードの引き算 EXCEPT(p231)

結合とは(p233)

別のテーブルから列を持ってきて「列を増やす」集合演算。

クロス結合 CROSS JOIN(p245)

実務で使うことはまずない。
2つのテーブルのレコードについて、すべての組み合わせを作るため、on句はない。
集合演算の掛け算にあたる。
全ての結合演算の基礎である。


内部結合は、必ずこのクロス結合の一部分になる(クロス結合の内部に含まれる)。
外部結合はその限りではない(クロス結合の結果に含まれない部分を持つ)。

第8章 SQLで高度な処理を行う

MySQL でも 8.0 からウィンドウ関数が使えるようになった。

ウィンドウ関数とは(p255)

別名OLAP(オーラップ)関数。Online Analytical Processingの略で、データベースを使ってリアルタイムにデータ分析を行う処理のこと。

<ウィンドウ関数> over ([partition by <列リスト>]
                                       order by <ソート用列リスト>);

ウィンドウ関数として使えるのは、下記の2種類
1. 集約関数(sum, avg, count, max, min)をウィンドウ関数として使う

2.rank, dense_rank, row_numberなどのウィンドウ専用関数

partition byは、順位をつける対象の範囲を指定する。テーブルを横方向にカットする。
order byは、どの列を、どんな順序で順位づけるかを指定する。縦方向に順位付けのルールを決める。

ウィンドウ関数はどこで使うか(p261)

原則としてselect句のみで使える。
なぜなら、ウィンドウ関数は、where句やgroup by句による処理が終わった「結果」に対して作用するから。ランキングを出した後にwhere句やgroup by句の処理を行ったら、順番が変わってしまう。

課題 理解しきれなかったところ

・相関サブクエリ(p170)
・exist述語(p212)
・関係除算(p249)
・第8章 ウィンドウ関数全体(p253-)