SELECT INTO 仅支持 SQL Server 同库内新建表并插入数据,不跨库跨实例,不兼容 MySQL/PostgreSQL;不复制索引约束,不可覆盖原表,需配合 DROP 和 sp_rename 使用。

SELECT INTO 不能跨数据库备份?先看它到底支持什么
SELECT INTO 是 SQL Server 特有的语句,** 不支持跨数据库、不支持跨实例、也不支持在 PostgreSQL / MySQL 中使用 **。它本质是“创建新表 + 插入数据”一步完成,目标表必须不存在,且只能在当前数据库内执行。
常见错误现象:Invalid object name 'otherdb.dbo.table' 或 Incorrect syntax near 'INTO'(在 MySQL 里直接报错)。
- 只适用于 SQL Server(2005 及以上)
- 目标表名不能带数据库前缀,如
mydb.dbo.backup_table会失败 - 源表和目标表必须在同一个数据库下
- 不会复制索引、约束、触发器——只拷贝数据和列定义(含 NULL/NOT NULL)
想快速备份再覆盖原表?别用 SELECT INTO 直接搞原表
直接 SELECT INTO 到原表名会报错:There is already an object named 'xxx' in the database。它拒绝覆盖已有表。
正确路径是:先用 SELECT INTO 备份出新表 → 再用 DROP TABLE + sp_rename 替换原表。比 INSERT INTO …… SELECT 更快,因为绕过日志完整记录(在简单 / 大容量日志恢复模式下)。
- 备份阶段用:
SELECT * INTO backup_orders_20240615 FROM orders - 替换阶段分两步:
DROP TABLE orders,再sp_rename 'backup_orders_20240615', 'orders' - 注意:
sp_rename不更新外键、视图、存储过程里的引用,后续需手动检查 - 若原表有标识列(IDENTITY),
SELECT INTO会保留该属性,但新表的种子值从头开始,可能影响业务逻辑
替代方案:用 INSERT INTO + TRUNCATE 更可控
当需要保留原表结构(含索引、约束、权限)时,SELECT INTO 就不合适了。此时应走 INSERT INTO …… SELECT + TRUNCATE TABLE 组合。
性能上略慢于 SELECT INTO(因全程记日志),但安全边界清晰,适合生产环境常规覆盖操作。
- 先清空:
TRUNCATE TABLE orders(比DELETE快,且重置标识种子) - 再灌入:
INSERT INTO orders SELECT * FROM orders_backup - 如果字段顺序或类型不一致,必须显式列出列名:
INSERT INTO orders(id, name) SELECT id, title FROM orders_backup - 目标表若有计算列、默认约束,
INSERT INTO默认不触发,需确认是否符合预期
MySQL / PostgreSQL 用户别硬套 SELECT INTO
MySQL 根本没有 SELECT INTO 表语法;PostgreSQL 的 SELECT INTO 是创建临时表,不是持久备份。
对应场景下,得换真实可用的命令:
- MySQL:用
CREATE TABLE orders_bak AS SELECT * FROM orders - PostgreSQL:用
CREATE TABLE orders_bak AS SELECT * FROM orders WITH DATA - 三者都支持
mysqldump/pg_dump做逻辑备份,但那是文件级,不是表内快速覆盖 - 跨库迁移时,别指望一条 SQL 解决——得靠导出导入或链接服务器(SQL Server)、FEDERATED 引擎(MySQL)、foreign data wrapper(PG)
事情说清了就结束。最常被忽略的是:SELECT INTO 创建的表没有主键、没有索引、也没有权限继承——你以为备份完了,其实刚起步。