テーブルを読む、作る
顧客一覧テーブルを操作しながら、行・列・主キー・データ型・NULL の役割を学び、実際にテーブルを作成してデータを投入します。
- 表の行・列・左端の番号・空欄は、それぞれ何と呼ばれ、どういう約束があるのか
- 列には「型」があるとはどういうことか
- 自分でテーブルを作って行を入れるには、何を書くか
まずはテーブルを開いてみる: 顧客一覧
表示された表を見ながら、データベースの基本用語を確認していきましょう。横 1 行が行(レコード)で、ここでは 1 人分の顧客データを表します。縦 1 列が列(カラム)で、name や email のように名前が付いています。そして、同じ構造の行が集まった表全体をテーブルと呼びます。
id の列: 主キー
左端の id は 1 から 10 までの番号で、同じ番号を持つ行は存在しません。このように「各行を一意に識別できる列」を主キー(PRIMARY KEY)と呼びます。 主キーには重複した値を入れられず、空(NULL)にすることもできません。画面右側の「テーブル定義」パネル(右端のボタンから開閉可能)で 🔑 アイコンが付いている列が主キーです。
なぜ顧客の名前を主キーにしないのでしょうか。同姓同名の人が登録される可能性がありますし、結婚などで名前が変わることもあります。 主キーは他のテーブルから「この顧客」を参照する際にも使われるため(第 4 章で詳しく学びます)、値が変わりうる項目を主キーにすると参照先もすべて書き換える必要が生じてしまいます。 そのため、実務では業務的な意味を持たない連番(サロゲートキー)を主キーによく利用します。
空欄: NULL
伊藤さんと小林さんの email 欄が空欄になっています。結果には NULL と表示されていますね。 NULL は「値が存在しない」ことを示す特別な目印であり、空文字 '' や数値の 0 とは明確に異なります。 「メールアドレスが空文字」なのではなく、「メールアドレスが未登録である」という状態を表しています。
NULL には、初学者がつまずきやすい重要な性質があります。クエリを実行する前に、何行返ってくるか予想してみてください。
結果は 0 行になったはずです。実は、NULL と何かを = で比較した結果は、真(TRUE)でも偽(FALSE)でもなく「不明(UNKNOWN)」となります。WHERE 句は条件が「真」である行だけを残す仕組みのため、結果が不明となった行は除外されてしまいます。 NULL かどうかを正しく判定するには、専用の構文を使用します。
WHERE の細かな使い方は次章で詳しく学びます。ここではまず、「NULL は = では検索できず、IS NULL を使う必要がある」というルールを押さえておきましょう。 この性質は、第 2 章や第 6 章でもさらに意外な形で登場します。
列の型
各列には「どんな形式のデータが入るか」の決まり(データ型)が定義されています。実際の定義を確認してみましょう。
Create Table 列に、このテーブルを作成したときの SQL 文が表示されています。name VARCHAR(40) NOT NULL のように、 列ごとに「データ型」と「NULL を許容するかどうか」が明記されています。型は各列に入れられるデータの種類とサイズを制限し、型に合わない不正なデータが入るのを防ぎます。実務でよく使われる基本の 6 つを以下にまとめました。
| 型 | 入るもの | この店での例 | 注意 |
|---|---|---|---|
INT / BIGINT | 整数 | id、数量、価格(円) | INT は約 ±21 億まで。明細のように増え続ける id には BIGINT を使います |
DECIMAL(10,2) | 正確な小数 | 税率、外貨の金額 | FLOAT / DOUBLE は計算誤差が出るため金額計算には使いません |
VARCHAR(n) | n 文字までの文字列 | 名前、メール、商品名 | 長いテキストには TEXT を使います |
DATETIME | 日時 | 注文日時、登録日時 | タイムゾーン情報を持たないため、実務では UTC で統一して格納することが一般的です |
BOOLEAN | 真偽(実体は 0 / 1) | 有効フラグ | |
JSON | 構造化データ | 配送先の付加情報 | 頻繁に検索条件として使う値は、通常の列として切り出すのが定石です |
NOT NULL と指定された列には NULL を入れられません(テーブル一覧パネルの NN マークが該当します)。 「値が入っていなくても問題ない列」以外は、原則として NOT NULL にするのがデータベース設計の基本です。 NULL を許容した列が増えると、アプリケーション側でも常に「NULL の場合の例外処理」を考慮し続けなければならなくなるためです。 ここまでに出てきた行・列・テーブル・主キー・NULL・型の関係を図で整理してみましょう。
テーブルの作成・登録・読み取り
顧客一覧を取得するチケットの要件自体は SELECT * FROM customers で確認できました。 ここでは一歩進んで、自分で新しいテーブルを定義し、データを追加する一連の流れを体験してみましょう。 例として「クーポン情報」を管理するテーブルを作成します。作成後に上のパネルの「更新」を押すと、新しいテーブルが追加されたことを確認できます。
構文は CREATE TABLE テーブル名 (列の定義, …) です。AUTO_INCREMENT は「新しい行を追加する際に番号を自動採番する」指定、DEFAULT は「値を指定しなかった場合の初期値」を意味します。 今回は期限のない無期限クーポンも扱えるようにするため、expires_at だけ NULL を許可しています。
データを挿入する構文は INSERT INTO テーブル名 (列名, …) VALUES (値, …) です。 INSERT 時に省略した列は AUTO_INCREMENT や DEFAULT の値で自動補完されますが、 NOT NULL かつ DEFAULT もない列を省略するとエラーになります。実際にエラーになる挙動を確かめてみましょう。
データベースは不整合なデータの混入を厳格に拒否します。この「不正なデータを絶対に保存させない」という仕組みこそが、 アプリケーションのバグからデータを守る最後の砦となります。 1 件目の INSERT で 5 つの列がどのように埋まったかを、テーブル定義と対比して確認してみましょう。
テーブルは同じ構造の行の集まりであり、各列には型が定義され、主キーが各行を一意に識別します。NULL は「値が存在しない」ことを示し、通常の比較では見つかりません。
確認
メールが登録されていない顧客を探すのに、email = NULL と書いてはいけないのはなぜか。
INSERT で列を省いても行が入る場合と、エラーになる場合の違いは何か。
主キーに名前ではなく、意味のない連番を使うのはなぜか。
次の章へ
顧客一覧の取得やテーブルの基本構造を理解できました。次のチケットは「未発送の注文を新しい順に 10 件取得する」という要件です。 全件を取得するのではなく、条件に合致する特定の行だけを目的の順序で取得する方法を学びます。 WHERE、ORDER BY、LIMIT を使いこなしていきましょう。