ひとり勉強ログ

ITエンジニアの勉強したことメモ

MySQL講座#09 データの登録(INSERT文の使い方)

INSERTとは

CREATE TABLEで作成した箱の中に「データ」を詰めていくことで、はじめてデータベースは有用なものとなる。このデータを詰めるために使うSQLが、INSERT(挿入)である。

INSERTを学習するため、「cojin2」という名前のテーブルを作成する。テーブルの内容は、列数が減り、power列の制約が「DEFAULT 0」になっている。

[sql] CREATE TABLE chojin2 (id CHAR(4) NOT NULL, name VARCHAR(100) NOT NULL, kana VARCHAR(100) NOT NULL, category VARCHAR(100) NOT NULL, attribute VARCHAR(100) NOT NULL, power INTEGER DEFAULT 0, created DATE NOT NULL, PRIMARY KEY (id)); [/sql]

INSERT文の基本構文

テーブルにデータを1行追加する。

[sql] INSERT INTO chojin2 (id, name, kana, category, attribute, power, created) VALUES ('0001', 'キン肉マン', 'きんにくまん', '正義超人', 'アイドル超人', '95', NOW()); [/sql]

id列(id)やname列(名前)は文字型なので、挿入する値も'0001'のようにシングルクォーテーションで囲む必要があります。これはcreated(登録日)のような日付型の列も同様である。

また、列名や値をカンマで区切って、外側をカッコ()でくくった形式をリストと呼ぶ。

列リスト→(id, name, kana, category, attribute, power, created)

値リスト→('0001', 'キン肉マン', 'きんにくまん', '正義超人', 'アイドル超人', '95', NOW())

当然のことながら、テーブル名の後の列リストと、VALUE句の値リストは、列数が一致している必がある。

また、INSERT文は、基本的に1回で1行を挿入する。したがって、複数の行を挿入したい場合は、原則的にその行数だけINSERT文も繰り返し実行する必要がある。

列リストの省略

テーブル名の後の列リストは、テーブルの全列に対してINSERTを行う場合、省略することができる。このとき、VALUE句の値が暗黙のうちに、左から順に各列に割り当てられる。したがって、以下のINSERT文はともに同じデータを挿入する。

列リストあり

[sql] INSERT INTO chojin2 (id, name, kana, category, attribute, power, created) VALUES ('0002', 'テリーマン', 'てりーまん', '正義超人', 'アイドル超人', '95', NOW()); [/sql]

列リストなし

[sql] INSERT INTO chojin2 VALUES ('0002', 'テリーマン', 'てりーまん', '正義超人', 'アイドル超人', '95', NOW()); [/sql]

NULLを挿入する

INSERT文で、ある列にNULLを割り当てたい場合は、VALUE句の値リストにNULLをそのまま記入する。例えば、power列(超人強度)にNULLを割り当てるには、以下のようなINSERT文になる。

[sql] INSERT INTO chojin2 (id, name, kana, category, attribute, power, created) VALUES ('0003', 'ロビンマスク', 'ろびんますく', '正義超人', 'アイドル超人', NULL, NOW()); [/sql]

ただし、NULLを割り当てられる列は、当然のことであるが、NOT NULL制約のついていない列に限られる。NOT NULL制約のついている列にNULLを指定した場合、INSERT文はエラーとなり、データの挿入に失敗する。

なお、「挿入に失敗する」とは、INSERT文を登録しようとしたデータが登録できなかった、ということである。これまでテーブルで登録されていたデータが消えたり壊れてしまうことはない。

デフォルト値を挿入する

テーブルの列には、デフォルト値(初期値)を設定することができる。デフォルト値を設定するには、テーブルを定義するCREATE TABLE文の中で、列に対してDEFAULT制約をつける。

chojin2テーブルの定義で、「DEFAULT 0」という箇所がDEFAULT制約を設定している部分。

テーブルの定義時にデフォルト値が設定されていた場合、自動的にそれをINSERT文の列の値として利用することができる。利用方法には、「明示的な方法」と「暗黙的な方法」がある。

①明示的にデフォルト値を挿入する

VALUES句にDEFAULTキーワードを指定する。

[sql] INSERT INTO chojin2 (id, name, kana, category, attribute, power, created) VALUES ('0003', 'ロビンマスク', 'ろびんますく', '正義超人', 'アイドル超人', DEFAULT, NOW()); [/sql]

こうすることで、RDBMSは自動的に列のデフォルト値を使用してレコードの挿入を行う。

暗黙的にデフォルト値を挿入する

デフォルト値の挿入は、DEFAULTキーワードを使用しなくても行うことが可能である。単純にデフォルト値が設定されている列を、列リストからもVALUESからも省略してしまえば良いのである。

[sql] INSERT INTO chojin2 (id, name, kana, category, attribute, created) VALUES ('0003', 'ロビンマスク', 'ろびんますく', '正義超人', 'アイドル超人', NOW()); [/sql]

この場合もやはりpowerにデフォルト値の0が使われる。

実際にはどちらの方法を使うのが良いか、という点が問題になる。私見ではあるが、「明示的な書き方」をおすすめする。なぜなら、こちらのほうがぱっと見てpowerにデフォルト値が利用されることが分かり、意味の捉えやすいSQLになるからである。

なお、列名の省略の話が出たついでに、もう1つ述べておくと、デフォルト値が設定されていない列を省略した場合は、NULLが割り当てられる。したがって、NOT NULL制約がつけられている列を省略すると、INSERT文はエラーになる。

ほかのテーブルからデータをコピーする

データを挿入する方法として、VALUES句で具体的なデータを指定する以外に、「ほかのテーブルから選択する」という方法もある。ここでは、あるテーブルのデータを選択し、それを別のテーブルへコピーして登録する方法を学ぶ。

まずサンプルテーブルを作る。

[sql] CREATE TABLE chojinCopy (id CHAR(4) NOT NULL, name VARCHAR(100) NOT NULL, kana VARCHAR(100) NOT NULL, category VARCHAR(100) NOT NULL, attribute VARCHAR(100) NOT NULL, height INTEGER NOT NULL, weight INTEGER NOT NULL, power INTEGER NOT NULL, origin VARCHAR(100) NOT NULL, created DATE NOT NULL, PRIMARY KEY (id)); [/sql]

chojinCopyテーブルのテーブル定義は、chojinテーブルを全く同じである。テーブル名だけを変えている。さっそく、chojinCopyテーブルにchojinテーブルのデータを挿入してみる。

SELECTした結果をそのままテーブルにINSERTすることができる。

[sql] INSERT INTO chojinCopy (id, name, kana, category, attribute, height, weight, power, origin, created) SELECT id, name, kana, category, attribute, height, weight, power, origin, created FROM chojin; [/sql]

INSERT … SELECT文を実行すると、元のchojinテーブルに44行のデータが入っていたとすれば、chojinCopyテーブルにも全く同じ44用のデータが追加される。INSERT … SELECT文は、データのバックアップをとるような場合にも使用することができる。

SELECT文のバリエーション

このINSERT文内のSELECT文には、WHERE句やGROUP BY句など使うことができる。テーブル同士でデータをやり取りしたい場合に便利な機能である。

例えば、GROUP BY句を使ったSELECT文をINSERTしてみる。INSERT先のテーブルとして、以下のテーブルを作る。

[sql] CREATE TABLE ChojinCategory (category VARCHAR(20) NOT NULL, avg_height INTEGER, avg_weight INTEGER, PRIMARY KEY (category)); [/sql]

超人の分類(category)ごとに身長の平均(avg_height)と体重の平均(avg_weight)を保持するためのテーブルである。ここに、chojinテーブルからデータを挿入するならば、以下のようにINSERT … SELECT文を使う。

[sql] INSERT INTO ChojinCategory (category, avg_height, avg_weight) SELECT category, AVG(height), AVG(weight) FROM chojin GROUP BY category; [/sql]

[sql] SELECT * FROM ChojinCategory; [/sql]

結果

[sql] +--------------+------------+------------+ | category | avg_height | avg_weight | +--------------+------------+------------+ | 完璧超人 | 231 | 271 | | 悪魔超人 | 215 | 404 | | 正義超人 | 199 | 90 | +--------------+------------+------------+ [/sql]