MySQL不支持SELECT INTO,会报ERROR 1064;应使用CREATE TABLE ... AS SELECT(CTAS)建表并插入数据,但不继承主键、索引、AUTO_INCREMENT等约束。

SELECT INTO 不能在 MySQL 中使用
MySQL 不支持 SELECT INTO 语句,直接执行会报错 ERROR 1064 (42000)。这是初学者最容易踩的坑——把 SQL Server 或 PostgreSQL 的语法直接照搬到 MySQL 环境里。
真正可用的替代方案是 CREATE TABLE ... AS SELECT(CTAS),它能一次性建表并插入数据,效果等价于 SELECT INTO。
- 不支持事务回滚建表操作(DDL 语句隐式提交)
- 新表字段类型、是否允许 NULL、默认值都由 SELECT 结果推断,**不会继承原表的主键、索引、注释、AUTO_INCREMENT 属性**
- 如果目标表已存在,语句直接失败,不支持
OR REPLACE(MySQL 8.0.23+ 才支持CREATE OR REPLACE TABLE)
PostgreSQL 中的 SELECT INTO 是函数内部用法
PostgreSQL 的 SELECT INTO **仅限 PL/pgSQL 函数体内使用**,用于把查询结果赋给变量或记录,不是建表语句。例如:
DO $$ DECLARE r RECORD; BEGIN SELECT 1 AS a, 'x' AS b INTO r; -- ✅ 合法:赋值给变量 RAISE NOTICE '%', r; END $$;
想在 PostgreSQL 中建表并填充数据,必须用 CREATE TABLE AS SELECT(或 SELECT * INTO new_table FROM ... —— 这个语法仅在旧版本或特定上下文中有效,且已被标记为过时)。
-
SELECT * INTO new_table FROM old_table在现代 PostgreSQL(12+)中默认禁用,需显式开启pg_catalog权限或改用标准 CTAS - CTAS 创建的表默认无主键、无索引,如需约束需后续
ALTER TABLE
SQL Server 的 SELECT INTO 是最接近原意的实现
SQL Server 支持标准的 SELECT INTO,且行为明确:创建新表 + 插入数据 + 自动推导结构(含 NULLability 和数据类型),但同样不复制索引、约束、触发器。
注意几个关键限制:
- 目标表名不能预先存在,否则报错
Msg 2714, Level 16 - 不能在包含计算列、FILESTREAM 列或稀疏列的源表上直接使用(会报
Msg 4951) - 目标表始终是堆表(无聚集索引),除非你手动加
WITH (DATA_COMPRESSION = ...)等选项(SQL Server 2016+) - 事务日志开销比
INSERT INTO ... SELECT小,因为最小化日志记录(在 SIMPLE / BULK_LOGGED 恢复模式下)
跨数据库安全迁移的实操建议
写可移植 SQL 时,别依赖 SELECT INTO。统一用 CREATE TABLE AS SELECT(PostgreSQL / MySQL / Oracle 都支持),再补约束和索引。
例如,要从 users 表抽样建新表 users_backup:
CREATE TABLE users_backup AS SELECT id, name, email FROM users WHERE created_at > '2024-01-01';
然后立刻补主键(否则后续更新/删除会很慢):
ALTER TABLE users_backup ADD PRIMARY KEY (id);
- MySQL 8.0.19+ 支持
CREATE TABLE ... AS SELECT后立即指定ENGINE=InnoDB,但不能指定列级约束 - Oracle 中该语句叫
CREATE TABLE ... AS SELECT,但默认不带 NOT NULL 约束,即使源列是 NOT NULL - 所有数据库中,
SELECT INTO的“建表”能力本质都是语法糖,底层仍是 DDL + DML 组合,不可当作原子操作依赖
最常被忽略的一点:无论哪种写法,新表都不会有原表的外键引用关系,也不会继承权限设置——这些必须单独处理。

















