INSERT ... SELECT 是 MySQL 複製表資料、跨表同步、ETL 萃取的核心語法。本文涵蓋單表複製、多表 JOIN 組合、視圖嵌套三大場景,並針對「衍生表必須有別名」、「不可加 VALUES」、「字段對應」等常見語法陷阱詳細解析。
INSERT INTO 目標表 (欄位1, 欄位2, ...)
SELECT 欄位1, 欄位2, ... FROM 來源表 [WHERE 條件];
NULLVALUES 關鍵字-- 完整複製
INSERT INTO hotel_ktv (title, price, number, date, area, content, num)
SELECT title, price, number, date, area, content, num FROM hotel_ktv;
-- 條件複製 (如複製狀態=1 的記錄)
INSERT INTO archive_orders SELECT * FROM orders WHERE status = 1;
需將多表關聯查詢結果寫入單一目標表:
INSERT INTO target_table (col_a, col_b, col_c)
SELECT t1.a, t2.b, t3.c
FROM table1 t1
JOIN table2 t2 ON t1.id = t2.t1_id
JOIN table3 t3 ON t2.id = t3.t2_id
WHERE t1.status = 'active';
-- ✅ 正確:衍生表加別名 tb
INSERT INTO a (f1, f2)
SELECT * FROM (
SELECT b.f1, c.f2 FROM b JOIN c ON b.id = c.b_id
) AS tb;
-- ❌ 錯誤:缺少別名
INSERT INTO a (f1, f2)
SELECT * FROM (SELECT b.f1, c.f2 FROM b JOIN c ON b.id = c.b_id);
-- ERROR 1248 (42000): Every derived TABLE must have its own alias
| 錯誤寫法 | 錯誤代碼 | 原因 | 正確寫法 |
|---|---|---|---|
INSERT ... VALUES SELECT ... | 1064 | INSERT ... SELECT 不能有 VALUES | 移除 VALUES |
| 子查詢無別名 | 1248 | 衍生表強制要求別名 | 加 AS tb |
| 欄位數不匹配 | 1136 | SELECT 列數 ≠ 目標欄位數 | 補齊/刪減欄位 |
| 自增欄位填值 | 無報錯但值被忽略 | 自增列建議不指定或填 NULL | 目標欄位列表略過自增欄位 |
CREATE TABLE new_table LIKE old_table;
INSERT INTO new_table SELECT * FROM old_table;
INSERT INTO all_logs SELECT * FROM logs_202301
UNION ALL SELECT * FROM logs_202302
UNION ALL SELECT * FROM logs_202303;
INSERT IGNORE / ON DUPLICATE KEY UPDATE-- 忽略重複主鍵/唯一鍵
INSERT IGNORE INTO target SELECT * FROM source;
-- 衝突時更新
INSERT INTO target (id, val) SELECT id, val FROM source
ON DUPLICATE KEY UPDATE val = VALUES(val);
WHERE id BETWEEN ...,配合事務提交LOAD DATA INFILE 或 mysqldump --tabINSERT ... SELECT 是資料搬遷的瑞士刀:單表複製、多表融合、歷史歸檔、測試造數,一條 SQL 搞定。記住「無 VALUES、衍生表要別名、欄位逐一對應」,避開 90% 語法坑。