將一張表的數據高效複製到另一張表是常見運維與開發需求。MySQL 支援 INSERT ... SELECT 語法,可實現全量、指定列、條件過濾、去重等多種場景。
INSERT INTO target_table SELECT * FROM source_table;
要求:兩表列數、順序、類型完全一致。
INSERT INTO target_table (col1, col2, col3)
SELECT col1, col2, col3 FROM source_table;
注意: 目標列與來源列一一對應、順序一致。
INSERT INTO target_table (id, name, status)
SELECT id, name, 1 FROM source_table WHERE create_time > '2023-01-01';
-- 方式 A:LEFT JOIN + IS NULL
INSERT INTO target_table (id, name)
SELECT s.id, s.name
FROM source_table s
LEFT JOIN target_table t ON s.id = t.id
WHERE t.id IS NULL;
-- 方式 B:NOT EXISTS(通常效能更好)
INSERT INTO target_table (id, name)
SELECT s.id, s.name
FROM source_table s
WHERE NOT EXISTS (SELECT 1 FROM target_table t WHERE t.id = s.id);
-- 方式 C:INSERT IGNORE(需目標表有唯一鍵)
INSERT IGNORE INTO target_table (id, name)
SELECT id, name FROM source_table;
INSERT INTO new_articles (article_id, title, content, author_id, created_at)
SELECT id, subject, body, user_id, post_date FROM old_articles;
INSERT INTO user_summary (user_id, name, level, total_orders)
SELECT u.id, u.username,
CASE WHEN u.exp > 1000 THEN 'VIP' ELSE 'NORMAL' END,
COUNT(o.id)
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
GROUP BY u.id, u.username, u.exp;
-- 存儲過程分批示例
DELIMITER //
CREATE PROCEDURE batch_copy()
BEGIN
DECLARE done INT DEFAULT 0;
DECLARE v_max_id BIGINT DEFAULT 0;
SELECT MAX(id) INTO v_max_id FROM source_table;
WHILE done = 0 DO
INSERT INTO target_table SELECT * FROM source_table
WHERE id > v_max_id - 10000 AND id <= v_max_id;
IF ROW_COUNT() = 0 THEN SET done = 1; END IF;
SET v_max_id = v_max_id - 10000;
COMMIT;
END WHILE;
END//
DELIMITER ;
ALTER TABLE target_table DISABLE KEYS; -- MyISAM
SET FOREIGN_KEY_CHECKS = 0;
SET UNIQUE_CHECKS = 0;
SET AUTOCOMMIT = 0;
-- 導入後恢復
INSERT ... SELECT。| 錯誤 | 原因 | 修正 |
|---|---|---|
| Column count doesn't match | 目標列與 SELECT 列數不一致 | 顯式列出目標列與 SELECT 列 |
| Duplicate entry for key 'PRIMARY' | 主鍵/唯一鍵衝突 | 使用 INSERT IGNORE / ON DUPLICATE KEY UPDATE / NOT EXISTS |
| Data truncated | 目標列長度/精度不足 | 調整目標表結構或 SELECT 中 CAST/SUBSTRING |
| Lock wait timeout | 大事務鎖衝突 | 分批提交、調大 innodb_lock_wait_timeout |