当前位置:  开发笔记 > 编程语言 > 正文

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

如何解决《如何在SQLServer2005中删除列的IDENTITY属性》经验,为你挑选了1个好方法。

我希望能够将带有标识列的表中的数据插入到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

上面的代码使用标识列创建了#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

请注意,只有在使用列列表且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

至于我为什么要这样做: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

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



1> Daren Thomas..:

你可以试试

SET IDENTITY_INSERT #Tmp_MyTable ON 
-- ... do stuff
SET IDENTITY_INSERT #Tmp_MyTable OFF

这将允许您选择进入#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

(导致错误"只有在使用列列表并且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

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

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

推荐阅读
路人甲
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有