INSERT INTO ... SELECT
SELECT文の結果を別テーブルに一括挿入する『INSERT INTO ... SELECT』の構文です。テーブル間のデータコピー、条件付き抽出、サブクエリとの組み合わせに使用します。
構文
-- SELECT結果をそのまま別テーブルに挿入します。 INSERT INTO 挿入先テーブル (列名1, 列名2, ...) SELECT 列名1, 列名2, ... FROM 参照元テーブル WHERE 条件; -- 列名を省略する場合はすべての列を選択します(列数と型を一致させます)。 INSERT INTO 挿入先テーブル SELECT * FROM 参照元テーブル; -- サブクエリと組み合わせます。 INSERT INTO 挿入先テーブル (列名1, 列名2) SELECT 列名1, 列名2 FROM 参照元テーブル WHERE 列名1 IN (SELECT 列名1 FROM 別テーブル);
構文一覧
| 構文 | 概要 |
|---|---|
| INSERT INTO テーブル名 (...) SELECT ... | SELECTの結果を挿入先テーブルに一括挿入します。VALUES句は不要です。 |
| SELECT * FROM テーブル名 | すべての列を選択して挿入します。列数と型が挿入先と一致している必要があります。 |
| WHERE句の組み合わせ | SELECT側にWHERE句を付けて、条件に合う行だけを挿入します。 |
| サブクエリとの組み合わせ | SELECT内でサブクエリを使い、別テーブルの値を参照した条件で絞り込めます。 |
| CREATE TABLE ... AS SELECT | テーブルの作成と同時にデータを挿入します。INSERT INTO ... SELECTと異なり、挿入先テーブルが存在しない場合に使用します。 |
サンプルコード
ラボメンのデータが入ったテーブルを用意し、INSERT INTO ... SELECT でコピーや条件付き挿入を行います。
SQL
-- ラボメンテーブルを作成します。
CREATE TABLE lab_members (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
role VARCHAR(50) NOT NULL,
iq INT
);
-- データを挿入します。
INSERT INTO lab_members (name, role, iq) VALUES
('岡部倫太郎', 'ラボ長', 170),
('牧瀬紅莉栖', '天才科学者', 190),
('椎名まゆり', 'コスプレイヤー', NULL),
('橋田至', 'ハッカー', 163),
('桐生萌郁', 'エンジニア', 155);
-- アーカイブ用テーブルを作成します(同じ列構成)。
CREATE TABLE lab_members_archive (
id INT NOT NULL,
name VARCHAR(50) NOT NULL,
role VARCHAR(50) NOT NULL,
iq INT
);
-- 全ラボメンをアーカイブテーブルにコピーします。
INSERT INTO lab_members_archive (id, name, role, iq)
SELECT id, name, role, iq
FROM lab_members;
条件を指定して一部の行だけを挿入します。
SQL
-- IQが160以上のメンバーだけを別テーブルに挿入します。
CREATE TABLE high_iq_members (
id INT NOT NULL,
name VARCHAR(50) NOT NULL,
iq INT NOT NULL
);
INSERT INTO high_iq_members (id, name, iq)
SELECT id, name, iq
FROM lab_members
WHERE iq >= 160;
同じテーブルへのコピーや、サブクエリを使った絞り込みも可能です。
SQL
-- 役割ごとにリスト化するテーブルを作成します。
CREATE TABLE scientist_list (
name VARCHAR(50) NOT NULL,
role VARCHAR(50) NOT NULL
);
-- サブクエリで「天才」を含む役割のメンバーだけを挿入します。
INSERT INTO scientist_list (name, role)
SELECT name, role
FROM lab_members
WHERE role IN (
SELECT DISTINCT role
FROM lab_members
WHERE role LIKE '%天才%' OR role LIKE '%エンジニア%'
);
CREATE TABLE ... AS SELECT でテーブルの作成とデータのコピーを同時に行います。
SQL
-- MySQL: CREATE TABLE ... AS SELECT でテーブルを新規作成しながらコピーします。 -- INSERT INTO ... SELECT と異なり、挿入先テーブルが存在しない場合に使います。 -- ただし、主キーや制約はコピーされません。 CREATE TABLE lab_members_copy AS SELECT id, name, role, iq FROM lab_members WHERE iq IS NOT NULL; -- PostgreSQL の場合は CREATE TABLE ... AS で同様に記述できます。 CREATE TABLE lab_members_copy AS SELECT id, name, role, iq FROM lab_members WHERE iq IS NOT NULL;
実行結果
-- lab_members_archive に全件コピーした後の確認。 SELECT * FROM lab_members_archive; -- +----+------------------+------------------+------+ -- | id | name | role | iq | -- +----+------------------+------------------+------+ -- | 1 | 岡部倫太郎 | ラボ長 | 170 | -- | 2 | 牧瀬紅莉栖 | 天才科学者 | 190 | -- | 3 | 椎名まゆり | コスプレイヤー | NULL | -- | 4 | 橋田至 | ハッカー | 163 | -- | 5 | 桐生萌郁 | エンジニア | 155 | -- +----+------------------+------------------+------+ -- high_iq_members(IQ 160以上)の確認。 SELECT * FROM high_iq_members; -- +----+------------------+-----+ -- | id | name | iq | -- +----+------------------+-----+ -- | 1 | 岡部倫太郎 | 170 | -- | 2 | 牧瀬紅莉栖 | 190 | -- | 4 | 橋田至 | 163 | -- +----+------------------+-----+ -- scientist_list(サブクエリで絞り込み)の確認。 SELECT * FROM scientist_list; -- +------------------+------------------+ -- | name | role | -- +------------------+------------------+ -- | 牧瀬紅莉栖 | 天才科学者 | -- | 桐生萌郁 | エンジニア | -- +------------------+------------------+ -- lab_members_copy(CREATE TABLE ... AS SELECT / NULLを除外)の確認。 SELECT * FROM lab_members_copy; -- +----+------------------+------------------+-----+ -- | id | name | role | iq | -- +----+------------------+------------------+-----+ -- | 1 | 岡部倫太郎 | ラボ長 | 170 | -- | 2 | 牧瀬紅莉栖 | 天才科学者 | 190 | -- | 4 | 橋田至 | ハッカー | 163 | -- | 5 | 桐生萌郁 | エンジニア | 155 | -- +----+------------------+------------------+-----+
データベース別の書き方
『INSERT INTO ... SELECT』の基本構文は主要なデータベースで共通して使用できます。
-- MySQL・PostgreSQL・SQL Server・Oracle・SQLite 共通 INSERT INTO lab_members_archive (id, name, role, iq) SELECT id, name, role, iq FROM lab_members;
テーブルを作成しながらデータをコピーする構文はデータベースによって異なります。MySQL・PostgreSQL・SQLite は『CREATE TABLE ... AS SELECT』を使用します。SQL Server は『SELECT ... INTO』、Oracle は『CREATE TABLE ... AS』を使用します。
-- MySQL / PostgreSQL / SQLite CREATE TABLE lab_members_copy AS SELECT * FROM lab_members; -- SQL Server(SELECT ... INTO) SELECT * INTO lab_members_copy FROM lab_members; -- Oracle CREATE TABLE lab_members_copy AS SELECT * FROM lab_members;
PostgreSQL では INSERT INTO ... SELECT の後に『RETURNING』句を付けて、挿入された行の値を取得できます。
-- PostgreSQL: 挿入した行のIDを返します。 INSERT INTO high_iq_members (id, name, iq) SELECT id, name, iq FROM lab_members WHERE iq >= 160 RETURNING id, name;
概要
『INSERT INTO ... SELECT』はSELECTの結果をそのまま別テーブルに挿入するため、VALUES句を使う必要がありません。テーブル間のデータコピー、集計結果の保存、条件付き移動などで活用できます。
SELECT側の列数・列の順序・データ型が挿入先の列と一致している必要があります。列数や型が合っていない場合はエラーになります。列名は挿入先側の列定義に従うため、SELECT側の列名は挿入先の列名と一致していなくても構いません。
『CREATE TABLE ... AS SELECT』は挿入先テーブルが存在しない場合に使用します。テーブルの作成とデータの挿入を1文で行えますが、主キーやインデックス・制約はコピーされません。制約を引き継ぐ必要がある場合は、先に『CREATE TABLE』でテーブルを作成してから『INSERT INTO ... SELECT』でデータをコピーしてください。
データの挿入については『INSERT』も参照してください。テーブル作成の詳細は『CREATE TABLE』を参照してください。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。