INSERT INTO ... SELECT 是表間數據流轉利器。本文聚焦進階場景:多表JOIN組合欄位、子查詢派生表必須別名、禁止VALUES關鍵字三大核心知識點。
-- 兩表直插
INSERT INTO db1.tbl (col1, col2) SELECT col1, col2 FROM db2.tbl;
需從表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 tb; -- 必須有別名!
關鍵點:子查詢結果集作為「派生表」參與外層SELECT,**MySQL強制要求派生表有別名**(AS tb),否則報錯:ERROR 1248 (42000): Every derived table must have its own alias。
INSERT INTO target (a_col, b_col, c_col, d_col)
SELECT a.id, b.name, c.code, d.value
FROM table_a a
JOIN table_b b ON a.id = b.a_id
JOIN table_c c ON b.id = c.b_id
JOIN table_d d ON c.id = d.c_id
WHERE a.status = 1;
無需子查詢包裹,直接多表JOIN選欄位插入,效能更優。
-- 錯誤寫法
INSERT INTO db1.tbl (col1, col2) VALUES SELECT col1, col2 FROM db2.tbl;
-- 報錯:You have an error in your SQL syntax
VALUES僅用於INSERT ... VALUES (...), (...)顯式值列表,**INSERT ... SELECT 不能加 VALUES**。
| 優化點 | 說明 |
|---|---|
| 目標表無索引/僅主鍵 | 大批次插入前DROP INDEX,插入後CREATE INDEX |
| 關閉唯一/外鍵檢查 | SET UNIQUE_CHECKS=0; SET FOREIGN_KEY_CHECKS=0; 結束後恢復 |
| 批次提交 | 大數據量分塊LIMIT 50000,避免長事務 |
| 順序插入 | 按主鍵順序SELECT,減少InnoDB頁分裂 |
| 並行導入 | 多線程分範圍插入(需業務允許) |
INSERT SELECT:SQL層面,支援複雜JOIN/轉換,中等效能LOAD DATA INFILE:直接讀文件進引擎,**效能高10-20倍**,但需文件權限、格式固定掌握派生表別名強制規則、多表JOIN組合模式、拒絕VALUES誤用,讓INSERT INTO SELECT成為你數據遷移的得力幹將。