I want to be able to insert data from a table with an identity column into a temporary table in SQL Server 2005.
The TSQL looks something like:
-- 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
The above code created #Tmp_Table with an identity column, and the insert subsequently fails with an error "An explicit value for the identity column in table '#Tmp_MyTable' can only be specified when a column list is used and IDENTITY_INSERT is ON."
Is there a way in TSQL to drop the identity property of the column in the temporary table without listing all the columns explicitly? I specifically want to use "SELECT *" so that the code will continue to work if new columns are added to MyTable.
I believe dropping and recreating the column will change its position, making it impossible to use SELECT *.
Update:
I've tried using IDENTITY_INSERT as suggested in one response. It's not working - see the repro below. What am I doing wrong?
-- 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
Note that the error message *"An explicit value for the identity column in table '#TmpMyTable' can only be specified when a column list is used and IDENTITY_INSERT is ON."* - I specifically don't want to use a column list as explained above.
Update 2 Tried the suggestion from Mike but this gave the same error:
-- 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
As for why I want to do this: MyTable is a staging table which can contain a large number of rows to be merged into another table. I want to process the rows from the staging table, insert/update my main table, and delete them from the staging table in a loop that processes N rows per transaction. I realize there are other ways to achieve this.
Update 3
I couldn't get Mike's solution to work, however it suggested the following solution which does work: prefix with a non-identity column and drop the identity column:
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's suggestion to store only the keys in the temporary table is also a good one, though in this specific case there are reasons I prefer to have all columns in the temporary table.