Insert into ... Select *, how to ignore identity? - sql

I have a temp table with the exact structure of a concrete table T. It was created like this:
select top 0 * into #tmp from T
After processing and filling in content into #tmp, I want to copy the content back to T like this:
insert into T select * from #tmp
This is okay as long as T doesn't have identity column, but in my case it does. Is there any way I can ignore the auto-increment identity column from #tmp when I copy to T? My motivation is to avoid having to spell out every column name in the Insert Into list.
EDIT: toggling identity_insert wouldn't work because the pkeys in #tmp may collide with those in T if rows were inserted into T outside of my script, that's if #tmp has auto-incremented the pkey to sync with T's in the first place.

SET IDENTITY_INSERT ON
INSERT command
SET IDENTITY_INSERT OFF

As identity will be generated during insert anyway, could you simply remove this column from #tmp before inserting the data back to T?
alter table #tmp drop column id
UPD: Here's an example I've tested in SQL Server 2008:
create table T(ID int identity(1,1) not null, Value nvarchar(50))
insert into T (Value) values (N'Hello T!')
select top 0 * into #tmp from T
alter table #tmp drop column ID
insert into #tmp (Value) values (N'Hello #tmp')
insert into T select * from #tmp
drop table #tmp
select * from T
drop table T

See answers here and here:
select * into without_id from with_id
union all
select * from with_id where 1 = 0
Reason:
When an existing identity column is selected into a new table, the new column inherits the IDENTITY property, unless one of the following conditions is true:
The SELECT statement contains a join, GROUP BY clause, or aggregate function.
Multiple SELECT statements are joined by using UNION.
The identity column is listed more than one time in the select list.
The identity column is part of an expression.
The identity column is from a remote data source.
If any one of these conditions is true, the column is created NOT NULL instead of inheriting the IDENTITY property. If an identity column is required in the new table but such a column is not available, or you want a seed or increment value that is different than the source identity column, define the column in the select list using the IDENTITY function. See "Creating an identity column using the IDENTITY function" in the Examples section below.
All credit goes to Eric Humphrey and bernd_k

Not with SELECT * - if you selected every column but the identity, it will be fine. The only way I can see is that you could do this by dynamically building the INSERT statement.

Just list the colums you want to re-insert, you should never use select * anyway. If you don't want to type them ,just drag them from the object browser (If you expand the table and drag the word, columns, you will get all of them, just delete the id column)

INSERT INTO #Table
SELECT MAX(Id) + ROW_NUMBER() OVER(ORDER BY Id)

set identity_insert on
Use this.

Might an "update where T.ID = #tmp.ID" work?

it gives me a chance to preview the data before I do the insert
I have joins between temp tables as part of my calculation; temp tables allows me to focus on the exact set data that I am working with. I think that was it. Any suggestions/comments?
For part 1, as mentioned by Kolten in one of the comments, encapsulating your statements in a transaction and adding a parameter to toggle between display and commit will meet your needs. For Part 2, I would needs to see what "calculations" you are attempting. Limiting your data to a temp table may be over complicating the situation.

Related

How to copy some records of table and change some columns before insert into this table again in sql server?

In my SQL Server table, I have a table whose PK is GUID with lots of records already.
Now I want to add records which only needs to change the COMMON_ID and COMMON_ASSET_TYPE column of some existing records.
select * from My_Table where COMMON_ASSET_TYPE = "ASSET"
I am writing sql to copy above query result, changing COMMON_ID value to new GUID value and COMMON_ASSET_TYPE value from "ASSET" to "USER", then insert the new result into My_Table.
I do not know how to write it since now I feel it is a trouble to insert records manually.
Update:
I have far more columns in table and most of them are not nullable, I want to keep all these columns' data for new records except above two columns.Is there any way if I do not have to write all these column names in sql?
Try to use NEWID if you want to create new guid:
INSERT INTO dbo.YourTable
(
COMMON_ID,
COMMON_ASSET_TYPE
)
select NEWID(), 'User' as Common_Asset_Type
from My_Table
where COMMON_ASSET_TYPE = "ASSET"
UPDATE:
As a good practice I would suggest to write all column names explicitly to have a clean and clear insert statement. However, you can use the following construction, but it is not advisable in my opinion:
insert into table_One
select
id
, isnull(name,'Jon')
from table_Two
INSERT INTO My_Table (COMMON_ID,COMMON_LIMIT_IDENTITY, COMMON_CLASS_ID,COMMON_ASSET_TYPE)
SELECT NEWID(), COMMON_LIMIT_IDENTITY, COMMON_CLASS_ID,'USER'
FROM My_Table
WHERE COMMON_ASSET_TYPE = 'ASSET'
If I've understood correctly you want to take existing records in your table, modify them, and insert them as new records in the same table.
I'll assume ID column contains the the GUID?
I'd first create a temporary table
CREATE TABLE #myTempTable(
ID UNIQUEIDENTIFIER,
Name varchar(max),
... etc
);
Fill this temp table with the records to change with your SELECT statement.
Change the records in the temp table using UPDATE statement.
Finally, Insert those "new" records back into the primary table. with INSERT INTO SELECT statement.
You will probably have to sandwitch the INSERT INTO SELECT with IDENTITY_INSERT (on/off):
SET IDENTITY_INSERT schema_name.table_name ON
SET IDENTITY_INSERT schema_name.table_name OFF
IDENTITY_INSERT "Allows explicit values to be inserted into the identity column of a table."

Insert value into an old identity field

I have a table which had an identity column.
for many reasons we had to remove the identity from that column.
I have a system that inserts a value to that table by the old way, passes null for the identity column.
is there a simple way to define identity column to receive a value in case it is passed to it, and if a value of null is passed, to make that table to set a unique value to that field that is not found in that table (act like identity).
What i mean is, if there is value, insert it.
And if the system tries to insert null act like an identity.
Thanks in advance.
A trigger seems like a good choice for this situation, but there are a lot of ways you can handle the situation.
The example below creates an INSTEAD OF insert trigger that gets the columns that were supposed to be inserted, and generates a new value via a function if the ID column is null.
CREATE TRIGGER myTrigger ON myTable
INSTEAD OF INSERT
AS
INSERT INTO myTable (myIDcolumn, anotherColumn)
SELECT COALESCE(myIDColumn, dbo.SomeMethodToCreateID), anotherColumn
FROM inserted
How that SomeTheodToCreateID function is to work is up to you. One thing you could do is change the SELECT to combine max plus row_number:
SELECT (COALESCE(myIDColumn,
(SELECT MAX(myIDColumn) FROM myTable) + ROW_NUMBER() OVER(ORDER BY anotherColumn)
)
...
Try This
DBCC CHECKIDENT ( '[dbo].[Customers]', RESEED, 1 )

Changing Column Datatype After Data Insertion

I'm currently trying to localize a database, and my strategy involves taking all localizable strings out of my various tables, and putting them into another table containing a StringID, a CultureID and the LocalizedString, which is then referenced within the original table by the StringID. The problem is that I need to change the datatype of the column containing the string from a varchar to an int and replace the string with its reference to the LocalizedStrings table.
I've already taken all my strings from the table and created entries in the LocalizedStrings table at this point using an INSERT INTO query. And my current efforts to solve my problem look like this:
SELECT column1, column2, ...
INTO TempTable
FROM OriginalTable
INNER JOIN LocalizedStrings
ON OriginalTable.StringColumn = LocalizedStrings.LocalizedString
ALTER TABLE OriginalTable
DROP COLUMN StringColumn
ALTER TABLE OriginalTable
ADD NameStringID int
INSERT INTO OriginalTable (NameStringID)
SELECT StringID FROM TempTable
DROP TABLE TempTable
However due to various nightmarish dependencies, I'm getting all kinds of exceptions trying to do this.
My question is, is there an easier way? I'd also considered just adding the new column and leaving the old one as a temporary workaround, but that's pretty messy.
ALTER TABLE OriginalTable
ADD NameStringID int
update OT
set NameStringID = LS.NameStringID
from OriginalTable OT
join LocalizedStrings LS on ls.StringColumn = OT.LocalizedString
You will need to repeat this process for every child table if they also used the StringColumn.
You will also need to adjust all stored procedures, queries, ORM mappings to use the new colulm.
Then when all have been changed, run
ALTER TABLE OriginalTable
DROP COLUMN StringColumn
And of course dropp the column onthe child tables too if need be.
If you know that all of your column contains integer values, what you can do is cast the column to integer, and create another one on the fly. Not sure if I am understand you correctly, but something similar to the following:
declare #test table(id varchar(50),name varchar(50))
insert into #test
select '1','Test 1'
insert into #test
select '2','Test 2'
select *, cast(id as int) as ConvertedToInt into #Result from #test
select * from #Result
drop table #Result

Query regarding SQL Insert in SQL Server?

I am using SQL Server 2008 and developing a project which is in maintenance phase.
I want to insert record in a table whose primary key is an Integer but not an identity. e.g. table name is tblFiles and fields are ID, FileName, FileContent.
Actually that table is in use so I don’t want to make any schema change in it. And I want the key after row insertion because I have to put that in another table. Existing values in the Id column are different integer, means not in sequence.
So I want the query that also returns me the Id value. So I want to insert only FileName and FileContent and some sort of sql to whom I can embed in my insert query which insert a unique Id and also send me that id
Well, if it's not an IDENTITY field - don't you already have to specify the "ID" in your insert for it to succeed ? If so - you already have the ID! Or what am I missing? Is the ID determined by a trigger or something??
If so, try this query:
INSERT INTO dbo.tblFiles(FileName, FileContent)
OUTPUT inserted.ID
VALUES ('yourfile.name', 'your contents')
This should return the newly inserted ID from the INSERT query.
Marc
Change the Columns Identity Specification > Is Identity to Yes.
The after inserting into the table you can
Select SCOPE_IDENTITY()
to get the integer that was just added and return this in your SP.
If you really can't edit the database schema maybe you could add another table to the database that has two columns called ID and CurrentDate. Make the ID column an Identity. In your code insert into this table first select SCOPE_IDENTITY() and then use the integer returned to insert as the ID in your tblFles table.
P.S. Stop prefixing your table with tbl that's so 1999. :)
You could create a unique integer, not so elegantly, using
SELECT MAX(ID) + 1 FROM tblFiles
And simply return this from your query or sproc as the case maybe. Otherwise follow as marc_s says if it is known already.
UPDATE: have to say, rather than this fudge as requested, I would strongly recommend pushing back hard and getting table changed so this is an identity column, as this is what is. all answers so far are simply fudges, mine especially.
so my final query look like...
Insert into dbo.tblData (Id, FName, LName)
output inserted.Id
values ((SELECT MAX(ID) + 1 FROM dbo.tblData), 'xyz', 'abc')
We can assign max(ID)+1 in to an integer variable, then we can Insert
Declare #ID int
Select #ID = ISNULL(MAX(ID),0) + 1 FROM tblFiles
INSERT INTO tblFiles
(
ID, FileName, FileContent
)
Select #ID,'FileName','FileContent'
This insertion is direct,
INSERT INTO tblFiles
(
ID, FileName, FileContent
)
Select (Select ISNULL(MAX(ID),0) + 1 FROM tblFiles),'FileName','FileContent'
Here we have to use ISNULL condition because there is no data in table then it will return Null. So ISNULL(MAX(ID),0) + 1 this condition will give Data is null then 0+1=1.
Thank you

Row number in Sybase tables

Sybase db tables do not have a concept of self updating row numbers. However , for one of the modules , I require the presence of rownumber corresponding to each row in the database such that max(Column) would always tell me the number of rows in the table.
I thought I'll introduce an int column and keep updating this column to keep track of the row number. However I'm having problems in updating this column in case of deletes. What sql should I use in delete trigger to update this column?
You can easily assign a unique number to each row by using an identity column. The identity can be a numeric or an integer (in ASE12+).
This will almost do what you require. There are certain circumstances in which you will get a gap in the identity sequence. (These are called "identity gaps", the best discussion on them is here). Also deletes will cause gaps in the sequence as you've identified.
Why do you need to use max(col) to get the number of rows in the table, when you could just use count(*)? If you're trying to get the last row from the table, then you can do
select * from table where column = (select max(column) from table).
Regarding the delete trigger to update a manually managed column, I think this would be a potential source of deadlocks, and many performance issues. Imagine you have 1 million rows in your table, and you delete row 1, that's 999999 rows you now have to update to subtract 1 from the id.
Delete trigger
CREATE TRIGGER tigger ON myTable FOR DELETE
AS
update myTable
set id = id - (select count(*) from deleted d where d.id < t.id)
from myTable t
To avoid locking problems
You could add an extra table (which joins to your primary table) like this:
CREATE TABLE rowCounter
(id int, -- foreign key to main table
rownum int)
... and use the rownum field from this table.
If you put the delete trigger on this table then you would hugely reduce the potential for locking problems.
Approximate solution?
Does the table need to keep its rownumbers up to date all the time?
If not, you could have a job which runs every minute or so, which checks for gaps in the rownum, and does an update.
Question: do the rownumbers have to reflect the order in which rows were inserted?
If not, you could do far fewer updates, but only updating the most recent rows, "moving" them into gaps.
Leave a comment if you would like me to post any SQL for these ideas.
I'm not sure why you would want to do this. You could experiment with using temporary tables and "select into" with an Identity column like below.
create table test
(
col1 int,
col2 varchar(3)
)
insert into test values (100, "abc")
insert into test values (111, "def")
insert into test values (222, "ghi")
insert into test values (300, "jkl")
insert into test values (400, "mno")
select rank = identity(10), col1 into #t1 from Test
select * from #t1
delete from test where col2="ghi"
select rank = identity(10), col1 into #t2 from Test
select * from #t2
drop table test
drop table #t1
drop table #t2
This would give you a dynamic id (of sorts)