如何在SQL Server 2005中删除列的IDENTITY属性

Joe*_*Joe 9 sql t-sql sql-server-2005

我希望能够将带有标识列的表中的数据插入到SQL Server 2005中的临时表中.

TSQL看起来像:

-- Create empty temp table
SELECT *
INTO #Tmp_MyTable
FROM MyTable
WHERE 1=0
...
WHILE ...
BEGIN
    ...
    INSERT INTO #Tmp_MyTable
    SELECT TOP (@n) *
    FROM MyTable
    ...

END
Run Code Online (Sandbox Code Playgroud)

上面的代码使用标识列创建了#Tmp_Table,然后插入失败并显示错误"只有在使用列列表且IDENTITY_INSERT为ON时,才能指定表'#Tmp_MyTable'中标识列的显式值."

TSQL中是否有一种方法可以删除临时表中列的标识属性而不显式列出所有列?我特别想使用"SELECT*",以便在将新列添加到MyTable时代码将继续工作.

我相信删除和重新创建列将改变其位置,使得无法使用SELECT*.

更新:

我已尝试在一个响应中建议使用IDENTITY_INSERT.它不起作用 - 见下面的repro.我究竟做错了什么?

-- Create test table
CREATE TABLE [dbo].[TestTable](
    [ID] [numeric](18, 0) IDENTITY(1,1) NOT NULL,
    [Name] [varchar](50) NULL,
 CONSTRAINT [PK_TestTable] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)
) 
GO
-- Insert some data
INSERT INTO TestTable
(Name)
SELECT 'One'
UNION ALL
SELECT 'Two'
UNION ALL
SELECT 'Three'
GO
-- Create empty temp table
SELECT *
INTO #Tmp
FROM TestTable
WHERE 1=0

SET IDENTITY_INSERT #Tmp ON -- I also tried OFF / ON
INSERT INTO #Tmp
SELECT TOP 1 * FROM TestTable

SET IDENTITY_INSERT #Tmp OFF 
GO
-- Drop test table
DROP TABLE [dbo].[TestTable]
GO
Run Code Online (Sandbox Code Playgroud)

请注意,只有在使用列列表且IDENTITY_INSERT为ON 时,才能指定错误消息"表'#TmpMyTable'中标识列的显式值". - 我特别不想使用如上所述的列列表.

更新2 尝试了迈克的建议,但这给出了同样的错误:

-- Create empty temp table
SELECT *
INTO #Tmp
FROM (SELECT
      m1.*
      FROM TestTable                 m1
          LEFT OUTER JOIN TestTable  m2 ON m1.ID=m2.ID
      WHERE 1=0
 ) dt

INSERT INTO #Tmp
SELECT TOP 1 * FROM TestTable
Run Code Online (Sandbox Code Playgroud)

至于我为什么要这样做:MyTable是一个临时表,可以包含大量要合并到另一个表中的行.我想处理登台表中的行,插入/更新我的主表,并在每个事务处理N行的循环中从登台表中删除它们.我意识到还有其他方法可以实现这一目标.

更新3

我无法让Mike的解决方案起作用,但是它建议使用以下解决方案:使用非标识列作为前缀并删除标识列:

SELECT CAST(1 AS NUMERIC(18,0)) AS ID2, *
INTO #Tmp
FROM TestTable
WHERE 1=0
ALTER TABLE #Tmp DROP COLUMN ID

INSERT INTO #Tmp
SELECT TOP 1 * FROM TestTable
Run Code Online (Sandbox Code Playgroud)

Mike建议只在临时表中存储密钥也是一个很好的建议,尽管在这种特殊情况下我有理由希望在临时表中包含所有列.

Dar*_*mas 7

你可以试试

SET IDENTITY_INSERT #Tmp_MyTable ON 
-- ... do stuff
SET IDENTITY_INSERT #Tmp_MyTable OFF
Run Code Online (Sandbox Code Playgroud)

这将允许您选择进入#Tmp_MyTable即使它有一个标识列.

但是,这不会工作:

-- Create empty temp table
SELECT *
INTO #Tmp_MyTable
FROM MyTable
WHERE 1=0
...
WHILE ...
BEGIN
    ...
    SET IDENTITY_INSERT #Tmp_MyTable ON 

    INSERT INTO #Tmp_MyTable
    SELECT TOP (@n) *
    FROM MyTable

    SET IDENTITY_INSERT #Tmp_MyTable OFF 
    ...    
END
Run Code Online (Sandbox Code Playgroud)

(导致错误"只有在使用列列表并且IDENTITY_INSERT为ON时才能指定表'#Tmp'中标识列的显式值.")

似乎没有办法没有实际删除列 - 但这将改变OP提到的列的顺序.丑陋的黑客:基于#Tmp_MyTable创建一个新表...

我建议您编写一个存储过程,该存储过程基于MyTable具有相同列(按顺序)的表名()创建临时表,但缺少标识属性.

您可以使用以下代码:

select t.name as tablename, typ.name as typename, c.*
from sys.columns c inner join
     sys.tables t on c.object_id = t.[object_id] inner join
     sys.types typ on c.system_type_id = typ.system_type_id
order by t.name, c.column_id
Run Code Online (Sandbox Code Playgroud)

了解反射在TSQL中的工作原理.我相信你将不得不循环遍历相关表的列,并执行动态(手工制作,存储在字符串中然后评估)alter语句到生成的表.

你介意为世界其他地方发布这样的存储过程吗?这个问题在其他论坛中似乎也出现了很多......


KM.*_*KM. 3

如果您只是按照您所描述的方式处理行,那么将前 N 个主键值选择到临时表中不是更好吗,如下所示:

CREATE TABLE #KeysToProcess
(
     TempID    int  not null primary key identity(1,1)
    ,YourKey1  int  not null
    ,YourKey2  int  not null
)

INSERT INTO #KeysToProcess (YourKey1,YourKey2)
SELECT TOP n YourKey1,YourKey2  FROM MyTable
Run Code Online (Sandbox Code Playgroud)

键不应该经常更改(我希望),但其他列这样做也没有什么坏处。

获取插入的@@ROWCOUNT,您可以在 TempID 上执行一个简单的循环,其中它将从 1 到 @@ROWCOUNT

和/或

只需将 #KeysToProcess 加入到您的 MyKeys 表中即可开始使用,无需复制所有数据。

这在我的 SQL Server 2005 上运行良好,其中 MyTable.MyKey 是一个标识列。

-- Create empty temp table
SELECT *
INTO #TmpMikeMike
FROM (SELECT
      m1.*
      FROM MyTable                 m1
          LEFT OUTER JOIN MyTable  m2 ON m1.MyKey=m2.MyKey
      WHERE 1=0
 ) dt

INSERT INTO #TmpMike
SELECT TOP 1 * FROM MyTable

SELECT * from #TmpMike
Run Code Online (Sandbox Code Playgroud)



编辑
此作品,没有错误...

-- Create empty temp table
SELECT *
INTO #Tmp_MyTable
FROM (SELECT
          m1.*
          FROM MyTable                 m1
              LEFT OUTER JOIN MyTable  m2 ON m1.KeyValue=m2.KeyValue
          WHERE 1=0
     ) dt
...
WHILE ...
BEGIN
    ...
    INSERT INTO #Tmp_MyTable
    SELECT TOP (@n) *
    FROM MyTable
    ...

END
Run Code Online (Sandbox Code Playgroud)

然而,你真正的问题是什么? 为什么在将“*”插入到这个临时表中时需要循环?您也许能够改变策略并提出一个总体上更好的算法。


归档时间:

查看次数:

16367 次

最近记录:

11 年,6 月 前