INTO 子句 (Transact-SQL)

SELECT…INTO 在默认文件组中创建一个新表并将来自查询的结果行插入新表中。若要查看完整 SELECT 语法,请参阅 SELECT (Transact-SQL)

主题链接图标Transact-SQL 语法约定

语法

[ INTO new_table ]

参数

  • new_table
    根据选择列表中的列和从数据源选择的行,指定要创建的新表名。

    new_table 的格式通过对选择列表中的表达式进行取值来确定。new_table 中的列按选择列表指定的顺序创建。new_table 中的每列与选择列表中的相应表达式具有相同的名称、数据类型、为 Null 性和值。列的 IDENTITY 属性将被转移,但在“备注”部分的“使用标识列”中定义的情况除外。

    若要在 SQL Server 的同一实例上的另一个数据库中创建该表,请将 new_table 指定为 database.schema.table_name 形式的完全限定名称。

    不能在远程计算机上创建 new_table,但可以从远程数据源填充 new_table。若要从远程源表创建 new_table,请在 SELECT 语句的 FROM 子句中按照 linked_server.catalog.schema.object 形式使用由四个部分组成的名称,指定源表。或者,您可以在 FROM 子句中使用 OPENQUERY 函数或 OPENDATASOURCE 函数指定远程数据源。

数据类型

FILESTREAM 属性不转移到新表。FILESTREAM BLOB 作为 varbinary(max) BLOB 复制并存储在新表中。如果没有 FILESTREAM 属性,则 varbinary(max) 数据类型具有 2 GB 的限制。如果某一 FILESTREAM BLOB 超出此值,则引发 7119 错误并停止该语句。

将现有标识列选入新表时,新列将继承 IDENTITY 属性,除非下列条件中的一个成立:

  • SELECT 语句包含联接、GROUP BY 子句或聚合函数。

  • 多个 SELECT 语句由 UNION 联接。

  • 标识列在选择列表内多次列出。

  • 标识列是表达式的一部分。

  • 标识列来自远程数据源。

如果这些条件中的一个为真,列将被创建为 NOT NULL 而不继承 IDENTITY 属性。如果在新表中需要某一标识列,但此类列不可用,或者您需要不同于源标识列的种子或增量值,则使用 IDENTITY 函数在选择列表中定义该列。请参阅下面的“示例”部分中的“使用 IDENTITY 函数创建标识列”。

限制和局限

不能将表变量或表值参数指定为新表。

即使源表已进行分区,您也不能使用 SELECT…INTO 创建已分区表。SELECT...INTO 不使用源表的分区方案;而是在默认文件组中创建新表。若要向已分区表插入行,首先必须创建已分区表,然后再使用 INSERT INTO...SELECT FROM 语句。

SELECT...INTO 不能与 COMPUTE 一起使用。

在源表中定义的索引、约束和触发器不转移到新表中,也不能在 SELECT...INTO 语句中指定它们。如果需要这些对象,则必须在执行 SELECT...INTO 语句后创建它们。

指定 ORDER BY 子句并不确保行按照指定的顺序插入。

当选择列表中包括稀疏列时,稀疏列属性不转移到新表中的列。如果新表中需要此属性,请在执行 SELECT...INTO 语句后更改列定义以包含此属性。

当选择列表中包括计算列时,新表中的相应列不是计算列。新列中的值是在执行 SELECT...INTO 时计算出的。

日志记录行为

SELECT...INTO 的日志记录量取决于对数据库有效的恢复模式。在简单恢复模式或大容量日志恢复模式下,大容量操作是最小日志记录操作。对于按最小方式记录日志,使用 SELECT… INTO 语句可能比创建一个表后使用 INSERT 语句填充该表效率更高。有关详细信息,请参阅可以尽量减少日志量的操作

权限

在目标数据库中要求 CREATE TABLE 权限。

示例

A. 通过指定来自多个源的列,创建一个表

下面的示例通过从与雇员有关的和地址有关的各个表中选择七列创建 dbo.EmployeeAddresses 表。

USE AdventureWorks2008R2;
GO
SELECT c.FirstName, c.LastName, e.JobTitle, a.AddressLine1, a.City, 
    sp.Name AS [State/Province], a.PostalCode
INTO dbo.EmployeeAddresses
FROM Person.Person AS c
    JOIN HumanResources.Employee AS e 
    ON e.BusinessEntityID = c.BusinessEntityID
    JOIN Person.BusinessEntityAddress AS bea
    ON e.BusinessEntityID = bea.BusinessEntityID
    JOIN Person.Address AS a
    ON bea.AddressID = a.AddressID
    JOIN Person.StateProvince as sp 
    ON sp.StateProvinceID = a.StateProvinceID;
GO

B. 使用最小日志记录插入行

下面的示例创建 dbo.NewProducts 表并从 Production.Product 表插入行。此示例假定 AdventureWorks2008R2 数据库的恢复模式设置为 FULL。若要确保最小方式记录,应在插入行之前将 AdventureWorks2008R2 数据库的恢复模式设置为 BULK_LOGGED,并在 SELECT...INTO 语句后重置为 FULL。此过程确保 SELECT...INTO 语句在事务日志中占用最少的空间并且高效执行。

USE AdventureWorks2008R2;
GO
IF OBJECT_ID ('dbo.NewProducts', 'U') IS NOT NULL
    DROP TABLE dbo.NewProducts;
GO
ALTER DATABASE AdventureWorks2008R2 SET RECOVERY BULK_LOGGED;
GO

SELECT * INTO dbo.NewProducts
FROM Production.Product
WHERE ListPrice > $25 
AND ListPrice < $100;
GO
ALTER DATABASE AdventureWorks2008R2 SET RECOVERY FULL;
GO

C. 使用 IDENTITY 函数创建标识列

下面的示例使用 IDENTITY 函数在新表 Person.USAddress 中创建一个标识列。这是必需的,因为定义该表的 SELECT 语句包含一个联接,而该联接导致 IDENTITY 属性不转移到新表。请注意,在 IDENTITY 函数中指定的种子和增量值不同于源表 Person.Address 的 AddressID 列中的种子和增量值。

USE AdventureWorks2008R2;
GO
IF OBJECT_ID ('Person.USAddress') IS NOT NULL
DROP TABLE Person.USAddress;
GO
-- Determine the IDENTITY status of the source column AddressID.
SELECT OBJECT_NAME(object_id) AS TableName, name AS column_name, is_identity, seed_value, increment_value
FROM sys.identity_columns
WHERE name = 'AddressID';

-- Create a new table with columns from the existing table Person.Address. A new IDENTITY
-- column is created by using the IDENTITY function.
SELECT IDENTITY (int, 100, 5) AS AddressID, 
       a.AddressLine1, a.City, b.Name AS State, a.PostalCode
INTO Person.USAddress 
FROM Person.Address AS a
INNER JOIN Person.StateProvince AS b ON a.StateProvinceID = b.StateProvinceID
WHERE b.CountryRegionCode = N'US'; 

-- Verify the IDENTITY status of the AddressID columns in both tables.
SELECT OBJECT_NAME(object_id) AS TableName, name AS column_name, is_identity, seed_value, increment_value
FROM sys.identity_columns
WHERE name = 'AddressID';

D. 通过指定来自远程数据源的列,创建一个表

下面的示例演示从远程数据源在本地服务器上创建新表的三个方法。该示例从创建指向远程数据源的链接开始。然后在第一个 SELECT...INTO 语句的 FROM 子句中和第二个 SELECT...INTO 语句的 OPENQUERY 函数中指定链接服务器名称 MyLinkServer,。第三个 SELECT...INTO 语句使用 OPENDATASOURCE 函数,该函数直接指定远程数据源,而非使用链接的服务器名称。

USE master;
GO
-- Create a link to the remote data source. 
-- Specify a valid server name for @datasrc as 'server_name' or 'server_name\instance_name'.
EXEC sp_addlinkedserver @server = N'MyLinkServer',
    @srvproduct = N' ',
    @provider = N'SQLNCLI', 
    @datasrc = N'server_name',
    @catalog = N'AdventureWorks2008R2';
GO
USE AdventureWorks2008R2;
GO
-- Specify the remote data source in the FROM clause using a four-part name 
-- in the form linked_server.catalog.schema.object.
SELECT *
INTO dbo.Departments
FROM MyLinkServer.AdventureWorks2008R2.HumanResources.Department
GO
-- Use the OPENQUERY function to access the remote data source.
SELECT *
INTO dbo.DepartmentsUsingOpenQuery
FROM OPENQUERY(MyLinkServer, 'SELECT *
               FROM AdventureWorks2008R2.HumanResources.Department'); 
GO
-- Use the OPENDATASOURCE function to specify the remote data source.
-- Specify a valid server name for Data Source using the format server_name or server_name\instance_name.
SELECT *
INTO dbo.DepartmentsUsingOpenDataSource
FROM OPENDATASOURCE('SQLNCLI',
    'Data Source=server_name;Integrated Security=SSPI')
    .AdventureWorks2008R2.HumanResources.Department;
GO