一時テーブルとは、データベースセッションの間だけ存在するテーブルです。行を入れて通常のテーブルと同じようにクエリでき、接続を切るとデータベースが自動的に削除してくれます。この記事の例は PostgreSQL、MySQL、SQLite、SQL Server で動作します。
SQL 一時テーブルの使い方
一時テーブルは、TEMPORARY キーワードを付けて通常のテーブルと同じように作成します。多くの場合、クエリの結果から直接データを入れます:
CREATE TEMPORARY TABLE table_name AS
SELECT ...;
SQL Server は例外で、名前の先頭に # を付けると一時テーブルになり、SELECT ... INTO で作成とデータ投入を同時に行います。
-- Input: orders
-- id | customer | total | status
-- ---+----------+-------+---------
-- 1 | Maria | 120 | paid
-- 2 | Tom | 35 | refunded
-- 3 | Priya | 89 | paid
CREATE TEMPORARY TABLE paid_orders AS
SELECT id, customer, total FROM orders WHERE status = 'paid';
-- SQL Server: SELECT id, customer, total INTO #paid_orders FROM orders WHERE status = 'paid';
SELECT * FROM paid_orders; -- #paid_orders in SQL Server
-- Output:
-- id | customer | total
-- ---+----------+------
-- 1 | Maria | 120
-- 3 | Priya | 89
永続テーブルと同じように、先に列を定義してから後で行を挿入することもできます:
CREATE TEMPORARY TABLE temp_students ( -- SQL Server: CREATE TABLE #temp_students (
student_id INT PRIMARY KEY,
first_name VARCHAR(50),
last_name VARCHAR(50),
age INT
);
INSERT INTO temp_students (student_id, first_name, last_name, age)
VALUES (1, 'John', 'Doe', 20);
SELECT * FROM temp_students;
-- Output:
-- student_id | first_name | last_name | age
-- -----------+------------+-----------+----
-- 1 | John | Doe | 20
知っておくべきルール
- 自分のセッションからしか見えません。他の接続からは読み取れず、セッションが終了するとデータベースが削除します。アプリケーションでコネクションプールを使っている場合は、一時テーブルの作成とクエリを同じ接続で行ってください。
-
同名の永続テーブルを隠してしまいます。
ordersという一時テーブルを作成すると、削除するまでordersへのクエリはすべて一時テーブルを参照します。名前が衝突しないようにしましょう。SQL Server の#プレフィックスならこの問題は起きません。 -
2回作成すると失敗します。同じセッションで同じスクリプトを2回実行すると、テーブルが既に存在するため
CREATEが失敗します。先に削除しておきましょう:
DROP TABLE IF EXISTS paid_orders;
-- In MySQL, DROP TEMPORARY TABLE IF EXISTS can never drop a permanent table by mistake
-
MySQL では1つのクエリで同じ一時テーブルを2回読めません。同じ一時テーブルへの自己結合やサブクエリは
ERROR 1137 (HY000): Can't reopen tableで失敗します。必要ならもう1つコピーを作成してください。
別の構文
-
CREATE TEMP TABLEは PostgreSQL と SQLite で使える短縮形です。MySQL では使えません。 -
SQL Server のグローバル一時テーブルは
##paid_ordersのように2つの # で始まります。すべてのセッションから読み取れ、作成したセッションが終了すると SQL Server が削除します。 - CTE は、1つのクエリだけで行が必要な場合に同じ役割を果たします。何も保存されないため、削除する必要もありません:
-- Input: the orders table above
WITH paid_orders AS (
SELECT id, customer, total FROM orders WHERE status = 'paid'
)
SELECT * FROM paid_orders;
-- Output:
-- id | customer | total
-- ---+----------+------
-- 1 | Maria | 120
-- 3 | Priya | 89
一時テーブルはいつ使うべき?
結果を複数のクエリで使いたいものの、セッションより長く残す必要はない場合に一時テーブルを使います。
同じ行を複数のクエリで再利用する
今月の注文やアクティブなプロジェクトなど、複数のレポートが同じ絞り込み結果から始まる場合は、一度保存して一時テーブルにクエリすれば、毎回同じ条件を繰り返す必要がありません。
絞り込みや再利用したい集計値を保存する
GROUP BY で一度集計し、その結果を一時テーブルに保存します。再計算せずに、絞り込みやランキング、平均値との比較ができます。
複雑なクエリをステップに分ける
サブクエリが何層にも重なったクエリは読みにくく、デバッグも大変です。各ステップを一時テーブルとして作成し、行を確認してから、次のステップで永続テーブルと結合しましょう。
コピーで変更を試す
本番データに UPDATE や DELETE を実行する前に、テーブルを一時テーブルにコピーしてそこで試しましょう。何が変わるかを確認でき、元のデータには影響しません。
SQL 一時テーブルの実例
SQL Server では、以下の一時テーブルを CREATE TEMPORARY TABLE の代わりに SELECT ... INTO #name で作成してください。
1か月分の注文で2つのレポートを作る
10月の注文を一度だけ一時テーブルに絞り込めば、好きなだけレポートを実行できます:
-- Input: orders
-- id | customer | order_date | total
-- ---+----------+------------+------
-- 1 | Maria | 2026-09-28 | 120
-- 2 | Tom | 2026-10-02 | 35
-- 3 | Maria | 2026-10-05 | 60
-- 4 | Priya | 2026-10-09 | 89
CREATE TEMPORARY TABLE october_orders AS
SELECT id, customer, total
FROM orders
WHERE order_date >= '2026-10-01' AND order_date < '2026-11-01';
SELECT COUNT(*) AS order_count, SUM(total) AS revenue
FROM october_orders;
-- Output:
-- order_count | revenue
-- ------------+--------
-- 3 | 184
SELECT customer, SUM(total) AS spent
FROM october_orders
GROUP BY customer
ORDER BY spent DESC;
-- Output:
-- customer | spent
-- ---------+------
-- Priya | 89
-- Maria | 60
-- Tom | 35
平均以上に購入している顧客を探す
顧客ごとの合計を保存し、その合計を平均と比較します:
-- Input: orders
-- id | customer | total
-- ---+----------+------
-- 1 | Maria | 120
-- 2 | Tom | 35
-- 3 | Maria | 60
-- 4 | Priya | 89
-- 5 | Priya | 70
CREATE TEMPORARY TABLE customer_totals AS
SELECT customer, SUM(total) AS spent
FROM orders
GROUP BY customer;
SELECT customer, spent
FROM customer_totals
WHERE spent > (SELECT AVG(spent) FROM customer_totals)
ORDER BY spent DESC;
-- Output:
-- customer | spent
-- ---------+------
-- Maria | 180
-- Priya | 159
この例は MySQL では動作しません。MySQL は1つのクエリで customer_totals を2回読めないためです(Can't reopen table)。先に別のクエリで平均を求めてください。
最近注文していない顧客を探す
まず顧客ごとの最新の注文を求め、それを顧客リストと結合します。大きなテーブルでは、一時テーブルにインデックスを作成すると結合が速くなります:
-- Input: customers
-- id | name
-- ---+------
-- 1 | Maria
-- 2 | Tom
-- 3 | Priya
-- Input: orders
-- id | customer_id | order_date
-- ---+-------------+-----------
-- 1 | 1 | 2026-09-30
-- 2 | 2 | 2026-05-14
-- 3 | 1 | 2026-04-02
-- Step 1: each customer's latest order
CREATE TEMPORARY TABLE last_orders AS
SELECT customer_id, MAX(order_date) AS last_order
FROM orders
GROUP BY customer_id;
-- Step 2: on big tables, index the column you'll join on
CREATE INDEX idx_last_orders ON last_orders (customer_id);
-- Step 3: customers with no order since July 1
SELECT c.name, l.last_order
FROM customers c
LEFT JOIN last_orders l ON l.customer_id = c.id
WHERE l.last_order IS NULL OR l.last_order < '2026-07-01'
ORDER BY c.name;
-- Output:
-- name | last_order
-- ------+-----------
-- Priya | NULL
-- Tom | 2026-05-14
DELETE で削除される行を確認する
古いキャンセル済み注文を整理したいですか?まずコピーに対して DELETE を実行し、残った行を確認しましょう:
-- Input: orders
-- id | customer | status | order_date
-- ---+----------+-----------+-----------
-- 1 | Maria | cancelled | 2025-11-03
-- 2 | Tom | shipped | 2025-12-19
-- 3 | Priya | cancelled | 2026-02-11
-- 4 | Maria | shipped | 2026-03-02
CREATE TEMPORARY TABLE orders_copy AS
SELECT * FROM orders;
DELETE FROM orders_copy
WHERE status = 'cancelled' AND order_date < '2026-01-01';
SELECT * FROM orders_copy;
-- Output:
-- id | customer | status | order_date
-- ---+----------+-----------+-----------
-- 2 | Tom | shipped | 2025-12-19
-- 3 | Priya | cancelled | 2026-02-11
-- 4 | Maria | shipped | 2026-03-02
-- The real table still has every row
SELECT COUNT(*) AS order_count FROM orders;
-- Output: 4
SQL 一時テーブルについてさらに学ぶ
このブログの記事:
- SQL CTE とサブクエリのガイド: 一時テーブルを使わずに CTE で済む場合
- SQL CREATE TABLE ガイド: 一時テーブルにも共通する列の型と制約
- 図解 SQL JOIN ガイド: 一時テーブルと永続テーブルの結合
- SQL GROUP BY ガイド: 一時テーブルによく保存する集計
- tempdb のチューニングで SQL Server のパフォーマンスを向上: SQL Server が一時テーブルを保存する場所
- 本番データベースで安全に作業する: 変更を実行する前にテストする他の方法
公式ドキュメント:
- PostgreSQL: CREATE TABLE (TEMPORARY)
- MySQL: CREATE TEMPORARY TABLE ステートメント
- SQLite: CREATE TABLE
- SQL Server: CREATE TABLE、一時テーブル
Beekeeper Studioは無料のオープンソースのデータベースGUIです
これまで使った中で最高のSQLクエリ&エディタツールです。データベースの管理に必要なものがすべて揃っています。 - ⭐⭐⭐⭐⭐ Mit
Beekeeper Studioは高速で直感的、そして使いやすいツールです。多数のデータベースに対応し、Windows、Mac、Linuxで快適に動作します。
Beekeeper Studio 利用者の声
「Beekeeper Studio は以前の SQL ワークフローを完全に置き換えました。高速で直感的で、データベース作業がまた楽しくなりました。」
「多くのデータベース GUI を試しましたが、Beekeeper は機能とシンプルさのバランスが完璧です。とにかくちゃんと動きます。」