INTO 子句 (Transact-SQL)

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

适用范围:SQL Server(SQL Server 2008 至当前版本),Windows Azure SQL Database(初始版本至当前版本)。

主题链接图标 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 子句中使用 OPENQUERYOPENDATASOURCE 函数来指定远程数据源。

数据类型

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

在选择现有标识列并将其插入到新表时,新列将继承 IDENTITY 属性,除非满足以下条件之一:

  • SELECT 语句包含一个联接。

  • 多个 SELECT 语句由 UNION 联接。

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

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

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

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

限制和局限

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

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

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

指定 ORDER BY 子句无法确保按指定顺序插入行。

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

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

日志记录行为

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

权限

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

示例

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

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

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 表插入行。 此示例假定 AdventureWorks2012 数据库的恢复模式设置为 FULL。 若要确保最小方式记录,应在插入行之前将 AdventureWorks2012 数据库的恢复模式设置为 BULK_LOGGED,并在 SELECT...INTO 语句后重置为 FULL。 此过程确保 SELECT...INTO 语句在事务日志中占用最少的空间并且高效执行。

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

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

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

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

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 函数,该函数直接指定远程数据源,而非使用链接的服务器名称。

**适用范围:**SQL Server 2008 到 SQL Server 2014。

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'AdventureWorks2012';
GO
USE AdventureWorks2012;
GO
-- Specify the remote data source in the FROM clause using a four-part name 
-- in the form linked_server.catalog.schema.object.
SELECT DepartmentID, Name, GroupName, ModifiedDate
INTO dbo.Departments
FROM MyLinkServer.AdventureWorks2012.HumanResources.Department
GO
-- Use the OPENQUERY function to access the remote data source.
SELECT DepartmentID, Name, GroupName, ModifiedDate
INTO dbo.DepartmentsUsingOpenQuery
FROM OPENQUERY(MyLinkServer, 'SELECT *
               FROM AdventureWorks2012.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 DepartmentID, Name, GroupName, ModifiedDate
INTO dbo.DepartmentsUsingOpenDataSource
FROM OPENDATASOURCE('SQLNCLI',
    'Data Source=server_name;Integrated Security=SSPI')
    .AdventureWorks2012.HumanResources.Department;
GO

请参阅

参考

SELECT (Transact-SQL)

SELECT 示例 (Transact-SQL)

INSERT (Transact-SQL)

IDENTITY(函数)(Transact-SQL)