🧚 お知らせ!Beekeeper Studio は高速でモダンなオープンソースのデータベース GUI です ダウンロード
2025年7月12日 著者: Matthew Rathbone

一時テーブルとは、データベースセッションの間だけ存在するテーブルです。行を入れて通常のテーブルと同じようにクエリでき、接続を切るとデータベースが自動的に削除してくれます。この記事の例は 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 一時テーブルについてさらに学ぶ

このブログの記事:

公式ドキュメント:

Beekeeper Studioは無料のオープンソースのデータベースGUIです

これまで使った中で最高のSQLクエリ&エディタツールです。データベースの管理に必要なものがすべて揃っています。 - ⭐⭐⭐⭐⭐ Mit

Beekeeper Studioは高速で直感的、そして使いやすいツールです。多数のデータベースに対応し、Windows、Mac、Linuxで快適に動作します。

BeekeeperのLinux版は100%フル機能。手抜きも機能の妥協も一切ありません。

Beekeeper Studio 利用者の声

★★★★★
「Beekeeper Studio は以前の SQL ワークフローを完全に置き換えました。高速で直感的で、データベース作業がまた楽しくなりました。」
— Alex K.、データベース開発者
★★★★★
「多くのデータベース GUI を試しましたが、Beekeeper は機能とシンプルさのバランスが完璧です。とにかくちゃんと動きます。」
— Sarah M.、フルスタックエンジニア