SQL Scale Lab
第一部 DB 基礎編 · 第 1 章 · 約 25 分

テーブルを読む、作る

顧客一覧テーブルを操作しながら、行・列・主キー・データ型・NULL の役割を学び、実際にテーブルを作成してデータを投入します。

この章で答える問い
  1. 表の行・列・左端の番号・空欄は、それぞれ何と呼ばれ、どういう約束があるのか
  2. 列には「型」があるとはどういうことか
  3. 自分でテーブルを作って行を入れるには、何を書くか

まずはテーブルを開いてみる: 顧客一覧

customers を全部
期待: 10 行 5 列。email が空の行が 2 つ

表示された表を見ながら、データベースの基本用語を確認していきましょう。横 1 行が行(レコード)で、ここでは 1 人分の顧客データを表します。縦 1 列が列(カラム)で、name や email のように名前が付いています。そして、同じ構造の行が集まった表全体をテーブルと呼びます。

id の列: 主キー

左端の id は 1 から 10 までの番号で、同じ番号を持つ行は存在しません。このように「各行を一意に識別できる列」を主キー(PRIMARY KEY)と呼びます。 主キーには重複した値を入れられず、空(NULL)にすることもできません。画面右側の「テーブル定義」パネル(右端のボタンから開閉可能)で 🔑 アイコンが付いている列が主キーです。

なぜ顧客の名前を主キーにしないのでしょうか。同姓同名の人が登録される可能性がありますし、結婚などで名前が変わることもあります。 主キーは他のテーブルから「この顧客」を参照する際にも使われるため(第 4 章で詳しく学びます)、値が変わりうる項目を主キーにすると参照先もすべて書き換える必要が生じてしまいます。 そのため、実務では業務的な意味を持たない連番(サロゲートキー)を主キーによく利用します。

空欄: NULL

伊藤さんと小林さんの email 欄が空欄になっています。結果には NULL と表示されていますね。 NULL は「値が存在しない」ことを示す特別な目印であり、空文字 '' や数値の 0 とは明確に異なります。 「メールアドレスが空文字」なのではなく、「メールアドレスが未登録である」という状態を表しています。

NULL には、初学者がつまずきやすい重要な性質があります。クエリを実行する前に、何行返ってくるか予想してみてください。

email が NULL の人を = で探す
期待: 予測してから実行
実行する前に予測する

結果は 0 行になったはずです。実は、NULL と何かを = で比較した結果は、真(TRUE)でも偽(FALSE)でもなく「不明(UNKNOWN)」となります。WHERE 句は条件が「真」である行だけを残す仕組みのため、結果が不明となった行は除外されてしまいます。 NULL かどうかを正しく判定するには、専用の構文を使用します。

IS NULL で探す
期待: 2 行

WHERE の細かな使い方は次章で詳しく学びます。ここではまず、「NULL は = では検索できず、IS NULL を使う必要がある」というルールを押さえておきましょう。 この性質は、第 2 章や第 6 章でもさらに意外な形で登場します。

列の型

各列には「どんな形式のデータが入るか」の決まり(データ型)が定義されています。実際の定義を確認してみましょう。

テーブルの定義を見る
期待: 1 行。Create Table の列に定義文

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・型の関係を図で整理してみましょう。

customers(10 行のうち 3 行)idnameemailtiercreated_at1佐藤 陽菜hina@example.comgold2025-11-03 13:512鈴木 大輔daisuke@example.comregular2025-12-14 09:525伊藤 結衣NULLregular2026-02-02 15:07……………← 1 行 = 1 人の顧客(レコード)↑ 列(カラム)id は主キー。行を一意に指し、重複も NULL も不可。NULL は「値がない」印。空文字とも 0 とも別物。列には型がある: INT / VARCHAR(40) / DATETIME。NOT NULL の列に NULL は入らない。
テーブルは同じ形の行の集まり。id が各行を一意に指し、NULL は値が存在しないことを示し、各列には型が定義されます。

テーブルの作成・登録・読み取り

顧客一覧を取得するチケットの要件自体は SELECT * FROM customers で確認できました。 ここでは一歩進んで、自分で新しいテーブルを定義し、データを追加する一連の流れを体験してみましょう。 例として「クーポン情報」を管理するテーブルを作成します。作成後に上のパネルの「更新」を押すと、新しいテーブルが追加されたことを確認できます。

coupons テーブルを作る
期待: エラーなく終わる(結果の表はない)

構文は CREATE TABLE テーブル名 (列の定義, …) です。AUTO_INCREMENT は「新しい行を追加する際に番号を自動採番する」指定、DEFAULT は「値を指定しなかった場合の初期値」を意味します。 今回は期限のない無期限クーポンも扱えるようにするため、expires_at だけ NULL を許可しています。

1 行入れる
期待: 影響した行数 1
まとめて入れる
期待: 影響した行数 3
読む
期待: 4 行。id は 1〜4、created_at は今の時刻

データを挿入する構文は INSERT INTO テーブル名 (列名, …) VALUES (値, …) です。 INSERT 時に省略した列は AUTO_INCREMENT や DEFAULT の値で自動補完されますが、 NOT NULL かつ DEFAULT もない列を省略するとエラーになります。実際にエラーになる挙動を確かめてみましょう。

NOT NULL の列を省く
期待: エラー。Field 'code' doesn't have a default value

データベースは不整合なデータの混入を厳格に拒否します。この「不正なデータを絶対に保存させない」という仕組みこそが、 アプリケーションのバグからデータを守る最後の砦となります。 1 件目の INSERT で 5 つの列がどのように埋まったかを、テーブル定義と対比して確認してみましょう。

INSERT INTO coupons (code, discount) VALUES ('WELCOME10', 10)列定義入った値idINT AUTO_INCREMENT PRIMARY KEY1codeVARCHAR(20) NOT NULL'WELCOME10'discountINT NOT NULL10expires_atDATETIME NULLNULLcreated_atDATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP今の時刻書かなかった → 自動採番書いた値書いた値書かなかった → NULL 許可なので NULL書かなかった → DEFAULT の値INSERT INTO coupons (discount) VALUES (15)idcodediscountexpires_atcreated_at…埋められない15NULL今の時刻code は NOT NULL で DEFAULT なし → エラー
省略した列は AUTO_INCREMENT・DEFAULT・NULL 許可のルールに従って自動的に埋まりますが、どれにも該当しない必須列を省くとエラーになります。

テーブルは同じ構造の行の集まりであり、各列には型が定義され、主キーが各行を一意に識別します。NULL は「値が存在しない」ことを示し、通常の比較では見つかりません。

確認

メールが登録されていない顧客を探すのに、email = NULL と書いてはいけないのはなぜか。
NULL と何かを = で比べた結果は真でも偽でもなく「不明」になり、WHERE は真の行しか残さないので 1 行も返らない。NULL かどうかを聞くには IS NULL を使う。
INSERT で列を省いても行が入る場合と、エラーになる場合の違いは何か。
AUTO_INCREMENT・DEFAULT・NULL 許可のどれかがある列は、省いてもその決まりで埋まる。NOT NULL で DEFAULT もない列を省くと、埋める値がないのでエラーになる。
主キーに名前ではなく、意味のない連番を使うのはなぜか。
主キーは他のテーブルから「この行」を指すのに使うため、値が変わると指している側を全部直すことになる。名前は同姓同名があり、変わりもするので向かない。

次の章へ

顧客一覧の取得やテーブルの基本構造を理解できました。次のチケットは「未発送の注文を新しい順に 10 件取得する」という要件です。 全件を取得するのではなく、条件に合致する特定の行だけを目的の順序で取得する方法を学びます。 WHERE、ORDER BY、LIMIT を使いこなしていきましょう。