mysql 5.7及更早版本不支持create table as select,正确写法为create table new_table select * from old_table;该语句仅复制数据和列类型,不复制主键、索引等约束,需手动添加。
create table as select 语法写对了但报错“syntax error near as”
常见于 mysql 5.7 及更早版本,或者用的是 mariadb 但启用了 sql_mode=strict_trans_tables 之类严格模式。mysql 直到 8.0.19 才正式支持标准的 create table as select(之前只支持 create table ... select,中间不能加 as)。
- 正确写法(兼容所有 MySQL 版本):
CREATE TABLE new_table SELECT * FROM old_table; - 带显式列定义时必须拆开:
CREATE TABLE new_table (id INT, name VARCHAR(50)) SELECT id, name FROM old_table; - PostgreSQL 和 SQL Server 支持
CREATE TABLE AS SELECT,但 PostgreSQL 要求必须用AS,不能省略;SQL Server 则用SELECT ... INTO new_table替代
新表没继承原表的主键、索引、NOT NULL 约束
CREATE TABLE AS SELECT 只复制数据和列类型,不复制任何约束或索引——这是设计行为,不是 bug。如果你需要主键或唯一索引,得手动补上。
- 执行完建表后立即加主键:
ALTER TABLE new_table ADD PRIMARY KEY (id); - 索引要单独建:
CREATE INDEX idx_name ON new_table (name); - 如果原表有
GENERATED COLUMN或DEFAULT表达式,MySQL 8.0+ 会保留默认值定义,但不会自动复制生成列逻辑,需检查SHOW CREATE TABLE确认
SELECT 中用了子查询或窗口函数,建表失败
某些数据库对 CREATE TABLE AS SELECT 的子句支持有限。比如 MySQL 不允许在 SELECT 中直接用 CTE(WITH),而 PostgreSQL 允许但要求整个 WITH 必须包裹在最外层。
- MySQL 下想用 CTE,得先建临时表或改用视图 +
CREATE TABLE ... SELECT两步走 - PostgreSQL 中正确写法:
CREATE TABLE new_table AS WITH tmp AS (SELECT ...) SELECT * FROM tmp; - 窗口函数一般没问题,但注意别在
SELECT里混用聚合和非聚合字段且没GROUP BY,否则建表时直接报错,不是数据问题而是语法校验失败
大数据量下建表卡住或 OOM
这条语句本质是把结果集全拉到服务端内存再写入新表,不是流式写入。几千万行以上就容易触发超时或内存溢出,尤其当 SELECT 还带 ORDER BY 或复杂 JOIN 时。
- 加
LIMIT测试是否语法/权限问题:CREATE TABLE test_small AS SELECT * FROM big_table LIMIT 1000; - 生产环境大表迁移,优先考虑
mysqldump --where或分批INSERT INTO ... SELECT+WHERE id BETWEEN ? AND ? - 确认
tmp_table_size和max_heap_table_size足够大,否则内部临时表会退化为磁盘表,大幅拖慢速度
最容易被忽略的是字符集和排序规则——CREATE TABLE AS SELECT 会继承源表字段的 COLLATE,但如果源表字段没显式声明,可能落到库级默认值,而目标库默认值不同,导致后续 JOIN 或 WHERE 比较异常。建完务必查 SHOW FULL COLUMNS FROM new_table; 核对。










