在資料庫開發中,常遇到從多張表抽取欄位組合後插入新表的需求。MySQL 支援 INSERT ... SELECT 語法,配合 JOIN 與子查詢,能以單一 SQL 完成跨表資料整合,大幅簡化程式碼邏輯。本文將從基礎語法進階至多表關聯實戰,並解析常見錯誤與最佳實踐。
最簡單的形式是將一張表的查詢結果直接插入另一張表:
INSERT INTO 目標表 (欄位1, 欄位2, ...) SELECT 欄位1, 欄位2, ... FROM 來源表 [WHERE 條件];
欄位順序、型別必須一一對應,WHERE 子句可過濾資料。
當需從表 b、c 取欄位合併插入表 a 時,直接 JOIN 查詢再包裹為子查詢即可:
INSERT INTO a (field1, field2)
SELECT * FROM (
SELECT b.f1, c.f2
FROM b
JOIN c ON b.id = c.b_id
) AS tmp_table;
關鍵點:
AS tmp_table),否則報錯 ERROR 1248 (42000): Every derived TABLE must have its own alias。SELECT * 前的欄位清單須與目標表欄位數量、順序一致。JOIN 即可,邏輯清晰且效能優於多次往返應用層。應用層常需寫入固定值(如用戶 IP、操作時間),可在 SELECT 列表混用常值與欄位:
INSERT INTO VoteRecord (IP, TopicNum, CreateTime) SELECT '192.168.1.1', MAX(ID), NOW() FROM Topic WHERE Content = '指定主題';
建議加上 MAX()、LIMIT 1 確保子查詢僅回傳單列,避免「Subquery returns more than 1 row」錯誤。
INSERT INTO aa (a, b, c, d, e, f, g, h) SELECT id, title, c, d, e, f, g, h FROM b WHERE id = 1;
此語句將表 b 中 id=1 的整列資料複製到表 aa,實現單條或批量資料遷移。
JOIN 條件欄位、WHERE 過濾欄位應建立索引,加速子查詢。LOAD DATA 替代。START TRANSACTION; ... COMMIT; 保證原子性。INSERT ... SELECT 搭配子查詢與 JOIN,是 MySQL 處理異構表資料整合的利器。掌握「衍生表必須別名」「欄位一一對應」「子查詢單列保護」三大原則,即可靈活應對多表合併插入、歷史資料歸檔、報表臨時表生成等場景,讓 SQL 承擔更多業務邏輯,減少應用層迴圈開銷。