我希望能够将带有标识列的表中的数据插入到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建议只在临时表中存储密钥也是一个很好的建议,尽管在这种特殊情况下我有理由希望在临时表中包含所有列.
你可以试试
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语句到生成的表.
你介意为世界其他地方发布这样的存储过程吗?这个问题在其他论坛中似乎也出现了很多......