SELECT INTO适用于目标表不存在的一次性操作,如临时备份、ETL中间表、测试造数或跨库迁移;它自动创建表结构并插入数据,但不复制主键、索引、约束等元数据,且要求目标表名未存在。

SELECT INTO 是 SQL Server 中最快创建新表并写入数据的方式,但它只适用于目标表不存在的场景,且不会复制主键、索引、约束、默认值、触发器等元数据。
什么时候该用 SELECT INTO?
它适合一次性操作:临时备份、ETL 中间表、测试环境快速造数、跨库迁移基础数据。不适合生产环境长期表复刻,因为缺失关键对象属性。
- 源表和目标表在同一个 SQL Server 实例内(支持跨库,如
SourceDB.dbo.Table1→TargetDB.dbo.Table2) - 你不需要原表的主键、外键、唯一约束、索引或
IDENTITY属性(除非显式启用IDENTITY传输) - 你确认目标表名尚未存在——否则语句直接报错:
There is already an object named 'xxx' in the database.
SELECT INTO 的三种典型写法
所有写法都遵循 SELECT ... INTO [new_table] FROM [source] 结构,区别只在 WHERE 条件和列选择上:
- 全量复制(含结构 + 所有行):
SELECT * INTO dbo.Customers_Backup FROM dbo.Customers; - 仅结构(空表):
SELECT * INTO dbo.Customers_StructureOnly FROM dbo.Customers WHERE 1 = 0; - 带条件筛选的数据复制:
SELECT CustomerID, Name, Email INTO dbo.Customers_2024Q1 FROM dbo.Customers WHERE CreatedDate >= '2024-01-01' AND CreatedDate
容易被忽略的细节和坑
SELECT INTO 表是“裸表”——它不继承任何原表的附加属性,这点必须提前认知:
-
IDENTITY列:只有当SELECT中直接引用原表的IDENTITY列(而非计算列或表达式),且目标表不存在时,新表才会自动获得IDENTITY属性;否则它只是普通INT - NULL 性:新表列的
NULL/NOT NULL状态由查询结果推断,若源列允许 NULL,但SELECT中用了ISNULL(col, ''),则新列会变成NOT NULL - 文件组:新表默认建在当前数据库的默认文件组,不能指定其他文件组(
ON filegroup语法虽存在,但仅限某些版本且不常用) - 权限:执行者需对源表有
SELECT权限,对目标数据库有CREATE TABLE权限
如果需要完整复制(含主键/索引/约束)怎么办?
不能靠 SELECT INTO 一步到位。正确路径是两步走:
- 先用
SELECT * INTO ... WHERE 1=0或 SSMS “生成脚本”功能导出结构(勾选“主键”“索引”“约束”等选项) - 再用
INSERT INTO ... SELECT ...填充数据(注意字段顺序、类型兼容性、大字段截断风险)
真正容易被跳过的点是:很多人以为 SELECT INTO 能“一键克隆”,结果上线后发现主键丢失、查询变慢(缺索引)、插入失败(缺 CHECK 约束),而这些都无法回退修复——新表一旦建好,就只能重建或手动补对象。










