不能。CREATE TABLE AS SELECT 仅复制查询结果的列名和类型,不保留主键、索引、外键、AUTO_INCREMENT、COMMENT、字符集、排序规则等元数据,需用 CREATE TABLE LIKE + INSERT 分两步实现完整复制。

MySQL 里用 CREATE TABLE AS SELECT 能不能直接复制主键和索引
不能。CREATE TABLE new_table AS SELECT * FROM old_table 只根据查询结果反推列名和类型,完全不读取原表的元数据。主键、唯一索引、外键、AUTO_INCREMENT、COMMENT、分区定义、字符集排序规则(除非显式指定)——全都不保留。
常见错误现象:执行完 SHOW CREATE TABLE new_table,发现 KEY 和 PRIMARY KEY 全是空的;后续插入时因无主键导致慢查询或应用报错;导出备份时被 mysqldump 跳过(尤其开启 --skip-triggers 时)。
实操建议:
- 只用于临时分析表、ETL 中间表、带时间戳的快照表(如
logs_20260521) - 若需保留主键,必须拆成两步:
CREATE TABLE new_table LIKE old_table+INSERT INTO new_table SELECT * FROM old_table - 注意浮点精度漂移:旧版 MySQL 可能把
DECIMAL(10,2)推导成DOUBLE,执行后用DESCRIBE new_table验证 - 字符集可能降级,例如原表是
utf8mb4_0900_as_cs,新表变成utf8mb4_0900_ai_ci,影响大小写敏感逻辑
SQL Server 里 SELECT INTO 报错 “There is already an object named 'xxx'” 怎么办
这是最典型的误用:目标表已存在。SELECT * INTO new_table FROM old_table 要求 new_table 在执行前绝对不存在,否则直接报错 Msg 2714, Level 16, State 6。
它不是“覆盖”,而是“创建并填充”,也不支持 IF NOT EXISTS 或 OR REPLACE 语法。
实操建议:
- 先用
IF OBJECT_ID('new_table', 'U') IS NOT NULL DROP TABLE new_table;清理再执行 - 在 Navicat 中执行前确认当前数据库上下文,写全三段名:
SELECT * INTO MyDB.dbo.new_table FROM MyDB.dbo.old_table - 如果只是想加个时间戳后缀,用动态 SQL 拼接表名,避免硬编码冲突
- 大表操作前检查事务日志空间,简单恢复模式下容易填满日志 —— 生产环境慎用,尤其没做日志备份时
跨库克隆时,为什么 mysqldump --no-data + --where="1=1" 比 CREATE TABLE AS SELECT 更稳
因为 mysqldump 直接读取 information_schema 和存储引擎元数据,能完整还原 CHARSET、COLLATE、COMMENT、AUTO_INCREMENT 当前值、分区定义、生成列逻辑、触发器(配合 --triggers),而 CREATE TABLE AS SELECT 连 COMMENT 都丢得干干净净。
实操建议:
- 同实例跨库:用
mysqldump -d --no-data db1 table1 | sed 's/`db1`/`db2`/g' | mysql db2建结构,再用mysqldump -t --where="1=1" db1 table1 | mysql db2导数据 - 不同实例间迁移:直接
mysqldump --single-transaction db1 table1 | mysql -h remote_host db2,比手写 CTAS + 补索引更少出错 - 如果必须用 CTAS,记得显式加
CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci,否则低版本客户端连接时可能降级
字段顺序不一致导致 JDBC rs.getString(1) 报错,怎么提前发现
这是最容易被忽略的隐性风险:CREATE TABLE AS SELECT 和 SELECT INTO 都按 SELECT 列顺序建表,但原表一旦新增字段(比如 ALTER TABLE ADD COLUMN at TIMESTAMP),新复制的表字段顺序就可能和旧应用预期不一致。
如果代码里硬编码了 rs.getString(1)、rs.getInt(2),而不是用列名访问,运行时就会取错字段,数值错位、类型转换失败。
实操建议:
- 复制前用
SELECT COLUMN_NAME FROM information_schema.COLUMNS WHERE TABLE_NAME = 'old_table' ORDER BY ORDINAL_POSITION记录原始顺序 - 复制后立即对比:
(SELECT COLUMN_NAME FROM information_schema.COLUMNS WHERE TABLE_NAME = 'new_table' ORDER BY ORDINAL_POSITION) EXCEPT (SELECT COLUMN_NAME FROM information_schema.COLUMNS WHERE TABLE_NAME = 'old_table' ORDER BY ORDINAL_POSITION) - 在 CI 流程中加入字段顺序校验脚本,避免人工疏漏
- 长期看,应推动应用改用
rs.getString("user_id")替代序号访问


















