Specify "NEXT VALUE" for INSERT statement using identity column in SQL Server - sql

Consider the following table and SQL from Microsoft's INSERT documentation that deals with IDENTITY columns:
CREATE TABLE dbo.T1 (column_1 int IDENTITY, column_2 VARCHAR(30));
GO
INSERT T1 (column_2) VALUES ('Row #2');
The INSERT statement does not specify column_1 as a column of the table, and SQL Server auto-populates the next value for that identity column. This is the normal way identity columns are handled.
How can I have the same behavior, while also specifying the column name?
For example, I'm looking for something like:
INSERT INTO T1 (column_1, column_2)
VALUES (NEXT VALUE, 'Row #3');
GO
I don't believe NEXT VALUE works here, but is there something that does work? Is there a key token or function that will indicate that the identity column should be used?
Note: the reason I ask is that the framework I'm using requires all columns to be specified in the column list.

If you are on SQL Server 2012 and later, you can use sequence. But you must remove the IDENTITY property from Column1 first. This can only be done by copy-and-rename a new table.
CREATE SEQUENCE Column1_Sequence
AS int
START WITH 0;
CREATE TABLE T1
(
Column1 int DEFAULT (NEXT VALUE FOR Column1_Sequence) PRIMARY KEY
, Column2 nvarchar(30)
)
After that, you can insert data into the table in 2 ways:
INSERT INTO T1 (Column1, Column2)
SELECT NEXT VALUE FOR Column1_Sequence
, 'Row #2'
INSERT INTO T1 (Column2)
SELECT 'Hello world'

Can you set the identity insert on before inserting and then set the identity insert off

You cannot set value for identity column unless you set identity_insert on for this table (one at time). Some examples:
create table #tmp (id int identity(1,1), name varchar(10))
insert #tmp (id,name) values (2,'test')
--error Cannot insert explicit value for identity column in table '#tmp
set identity_insert #tmp on --for one table in DB
insert #tmp (id,name) values (2,'qwas')
select * from #tmp
set identity_insert #tmp off -- good practice
--works
--see current identity value
SELECT IDENT_CURRENT ('#tmp') AS Current_Identity;
--Reset identity value
DBCC CHECKIDENT (#tmp, RESEED, 999)
--next insert will be 1000
Of course, if you reset next identity to a value which conflicts with PK (common usage of identity) you will have Violation of PRIMARY KEY constraint error

I am pretty sure there is no way to do that with SQL Server. Two workarounds that I can think of:
Fix the library if possible.
If the library supports it, you can create a view and INSERT into that instead. For example:
CREATE TABLE MyTable
(
ID INT IDENTITY(1, 1),
SomeColumn VARCHAR(100)
)
GO
CREATE VIEW MyTableView
AS
SELECT SomeColumn
FROM MyTable
GO
INSERT INTO MyTableView (SomeColumn) VALUES ('Test')

Related

Using ##identity for consecutive inserts

I have this situation,
INSERT INTO TABLE1()...
--Get the primary key from the above insert
SELECT ##identidy
INSERT INTO TABLE2()...
The auto generated primary key has to be a foreign key in TABLE 2. How can I construct my second INSERT to have the value of ##identity?
This doesn't seem to work,
INSERT INTO TABLE1 (user_id, name) (##identity, 'ABC')
I get an error saying Must declare variable '##identidy'.
Cheers!!
1) you spelled ##identity wrong (##identidy)
2) You should create a local variable (#LastIdentity) to store the last inserted identity immediately after the first insert. Then use that variable as the input to the second INSERT:
DECLARE #LastIdentity int
INSERT INTO TABLE1()...
--Get the primary key from the above insert
SELECT #LastIdentity = ##identity
INSERT INTO TABLE2(...) VALUES (#LastIdentity, ...

Convert an existing Column to Identity

I have a table in SQL Server with bundle of records. I want to convert the ID column which is Primary Key to an identity Column without loss of data. I thought of the following two approaches:
Create a new table with identity & drop the existing table.
Create a new column with identity & drop the existing column.
but it's clear that they can not be implemented because keeping records is my first priority.
Is there another way to do this?
This solution violates your point 2, but there is no other way and I think your aim is to keep the old values, because nothing else makes sense...
You could do the following:
make it possible to insert into identity columns in your table:
set identity_insert YourTable ON
add a new ID column to your table with identity and insert the values from your old columns
turn identity insert off
set identity_insert YourTable OFF
delete old ID column
rename new column to old name
make it to the primary key
The only problem could be that you have your ID column already connected as foreign key to other tables. Then you have a problem with deleting the old column...
In this case you have to drop the foreign key constraints on your ID column after step 3, then do step 4 to 6 and then recreate your foreign key constraints.
As you are using SQL Server 2012, another possible alternative could be to create a sequence object that has a starting value of the highest ID +1 already in your table, then create a default constraint for your column using GET NEXT VALUE FOR and reference your sequence object you just created.
If you have direct access to the Server Database, just go into the design of the table, select the PK column, and change the identity to "Yes". Make sure you set your seed to the max value of that column. The increment is 1 by default. Save the table design and you should be good to go.
Considering the source table isn't too big:
Create new table (with IDENTITY)
Populate new table from existing table (with IDENTITY_INSERT ON)
Drop old table (drop any existing FKs first)
Rename new table to old name (re-establish FKs if needed)
-- Create Sample Existing Table
DROP TABLE IF EXISTS #tblTest
CREATE TABLE #tblTest
(
ID INT NOT NULL
, Val VARCHAR(10) NOT NULL
)
INSERT INTO #tblTest
(
ID
, Val
)
VALUES
(1, 'a')
, (2, 'b')
, (4, 'c')
GO
-- Create and Populate New Table (with IDENTITY_INSERT ON)
DROP TABLE IF EXISTS #tblTestNew
CREATE TABLE #tblTestNew
(
ID INT IDENTITY(1, 1) NOT NULL
, Val VARCHAR(10) NOT NULL
)
SET IDENTITY_INSERT #tblTestNew ON
INSERT INTO #tblTestNew
(
ID
, Val
)
(
SELECT
#tblTest.ID
, #tblTest.Val
FROM
#tblTest
)
SET IDENTITY_INSERT #tblTestNew OFF
GO
-- Rename Existing Table to Old (can use sp_rename instead, but I can't for temp tables)
SELECT * INTO #tblTestOld FROM #tblTest
DROP TABLE #tblTest
GO
-- Rename New Table to Existing (can use sp_rename instead, but I can't for temp tables)
SELECT * INTO #tblTest FROM #tblTestNew
DROP TABLE #tblTestNew
GO
-- Test Inserting new record
INSERT INTO #tblTest (Val)
VALUES ('d')
-- Verify Results
SELECT * FROM #tblTest
EXEC tempdb.sys.sp_help #objname = N'#tblTest'
-- Drop 'Old' Table (when ready)
DROP TABLE IF EXISTS #tblTestOld
-- Cleanup
DROP TABLE IF EXISTS #tblTest
DROP TABLE IF EXISTS #tblTestNew
DROP TABLE IF EXISTS #tblTestOld
If the table is very large, consider the log growth, Recovery Model, possible single-user mode, etc.
create table t1 (col1 int, col2 varchar(10))
insert into t1 values (10, 'olddata')
--add identity col
alter table t1 add col3 int identity(1,1)
GO
--rename or remove old column
alter table t1 drop column col1
--rename new col to old col name
exec sp_rename 't1.col3', 'col1', 'column'
GO
--add new test , review table
insert into t1 values ( 'newdata')
select * from t1

set identity on the column

How can I modify table and set identity on PK column using T-SQL?
thanks for help
You can't modify an existing column to have the IDENTITY "property" - you have to:
create a new table with the same structure (but with IDENTITY set up),
turn on IDENTITY_INSERT for this new table,
insert rows from the old table into the new table,
drop the old table, and,
rename the new table to have the old table name.
If there are foreign keys involved, you need to fix those up also.
The problem with most solutions to this question is that they require either adding a new column to the table or completely rebuilding the table.
Both can require large amounts of locking and logging activity which I have always found annoying as this is a metadata only change and shouldn't necessitate touching the data pages at all (Indeed it is possible to update the metadata directly by starting the instance in single user mode and messing around with some columns in sys.syscolpars but this is undocumented/unsupported.)
However the workaround posted on this connect item shows a completely supported way of making this into a metadata only change using ALTER TABLE...SWITCH (credit SQLKiwi)
Example code.
Set up test table with no identity column.
CREATE TABLE dbo.tblFoo
(
bar INT PRIMARY KEY,
filler CHAR(8000),
filler2 CHAR(49)
)
INSERT INTO dbo.tblFoo (bar)
SELECT TOP (10000) ROW_NUMBER() OVER (ORDER BY (SELECT 0))
FROM master..spt_values v1, master..spt_values v2
Alter it to have an identity column (more or less instant).
BEGIN TRY;
BEGIN TRANSACTION;
/*Using DBCC CHECKIDENT('dbo.tblFoo') is slow so use dynamic SQL to
set the correct seed in the table definition instead*/
DECLARE #TableScript nvarchar(max)
SELECT #TableScript =
'
CREATE TABLE dbo.Destination(
bar INT IDENTITY(' +
CAST(ISNULL(MAX(bar),0)+1 AS VARCHAR) + ',1) PRIMARY KEY,
filler CHAR(8000),
filler2 CHAR(49)
)
ALTER TABLE dbo.tblFoo SWITCH TO dbo.Destination;
'
FROM dbo.tblFoo
WITH (TABLOCKX,HOLDLOCK)
EXEC(#TableScript)
DROP TABLE dbo.tblFoo;
EXECUTE sp_rename N'dbo.Destination', N'tblFoo', 'OBJECT';
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
IF XACT_STATE() <> 0 ROLLBACK TRANSACTION;
PRINT ERROR_MESSAGE();
END CATCH;
Test the result.
INSERT INTO dbo.tblFoo (filler,filler2)
OUTPUT inserted.*
VALUES ('foo','bar')
Gives
bar filler filler2
----------- --------- ---------
10001 foo bar
Clean up
DROP TABLE dbo.tblFoo
Is it the answer you are looking for?
DBCC CHECKIDENT(
'DBName.dbo.TableName'
,RESEED --[, new_reseed_value ]
)
Example use:
DBCC CHECKIDENT(
'DBName.dbo.TableName'
)
Checking identity information: current identity value '1', current column value '1211031236'.
DBCC execution completed. If DBCC printed error messages, contact your system administrator.
DBCC CHECKIDENT(
'DBName.dbo.TableName'
,RESEED --[, new_reseed_value ]
)
Checking identity information: current identity value '1211031236', current column value '1211031236'.
DBCC execution completed. If DBCC printed error messages, contact your system administrator.
In fact, you can modify the IDENTITY on a column.
Please read through this article http://www.sqlmag.com/article/tsql3/adding-the-identity-property-to-an-existing-column.aspx
It will need a lot more code than ALTER TABLE tab ALTER COLUMN col SET IDENTITY, though
You need to use the ALTER TABLE command - always test first in dev or pre-production!
The example G seems closest to your requirement:
CREATE TABLE dbo.doc_exe ( column_a INT CONSTRAINT column_a_un UNIQUE) ;
GO
ALTER TABLE dbo.doc_exe ADD
-- Add a PRIMARY KEY identity column.
column_b INT IDENTITY
CONSTRAINT column_b_pk PRIMARY KEY,
See http://msdn.microsoft.com/en-us/library/ms190273.aspx
Since you can only ignore identity columns for insert, not for update, you'll need an intermediate table. Here's an example:
create table TestTable (pk int constraint PK_TestTable primary key,
name varchar(30))
create table TestTable2 (pk int constraint PK_TestTable identity primary key,
name varchar(30))
set identity_insert TestTable2 on
insert TestTable2 (pk, name) select pk, name from TestTable
set identity_insert TestTable2 off
drop table TestTable
exec sp_rename 'TestTable2', 'TestTable'

how to enter values in rowguid column?

can anyone please tell me the right way to insert values in the rowguid column of the table? I m using sql server management studio
use the NEWID() function to generate one:
CREATE TABLE myTable(GuidCol uniqueidentifier
,NumCol int)
INSERT INTO myTable Values(NEWID(), 4)
SELECT * FROM myTable
or you can set it as a default value:
CREATE TABLE myTable(GuidCol uniqueidentifier DEFAULT NEWSEQUENTIALID()
,NumCol int)
INSERT INTO myTable (NumCol) Values(4)
SELECT * FROM myTable
You can Set NEWSEQUENTIALID() as Default in table
CREATE TABLE GuidTable
(
ID UNIQUEIDENTIFIER DEFAULT NEWSEQUENTIALID() PRIMARY KEY,
TEST INT
)
Read more about it here
http://msdn.microsoft.com/en-us/library/ms189786.aspx
It's a uniqueidentifier column
You can send a value like "6F9619FF-8B86-D011-B42D-00C04FC964FF", or use NEWID/NEWSEQUENTIALID functions to generate one
I was able to insert by using the following:
Insert Into Table FOO(Col1, Col2, RowGuidCol)
Values (5,'Hello,'1A49243F-1B57-5848-AA62-E4704544BB34')
It is very important to follow to place the dashes in the correct place. You do not need to have the 0x in the beginning of the string. FYI-Updates are not allow on columns whith the rowguid col property set. I hope this helps.
Assuming that you have a uniqueidentifier column rg in your table t which is set to be the rowguid:
INSERT INTO TABLE t (rg) VALUES (NEWID())
or
INSERT INTO TABLE t (rg) VALUES (NEWSEQUENTIALID())

How do I insert into a table and get back the primary key value?

I have a primary key set up to auto increment.
I am doing multiple queries and I need to retrieve that primary key value to use as a foreign key in another table (IsIdentity = TRUE).
Is there any elegant way to get back the primary key value when I do an insert query? Right now I am requerying and getting the highest value in that column which seems really hacky.
Any suggestions?
If you are using SQL Server 2005 or later, you can use the OUTPUT clause.
create table T(
pk int identity primary key,
dat varchar(20)
);
go
insert into T
output inserted.pk
values ('new item');
go
drop table T;
The output can be directed to a table as well as to the client. For example:
create table T(
pk int identity primary key,
dat varchar(20)
);
create table U(
i int identity(1001,1) primary key,
T_pk int not null,
d datetime
);
go
insert into T
output inserted.pk, getdate()
into U(T_pk,d)
values ('new item'), ('newer item');
go
select * from T;
select * from U;
go
drop table T, U;
Beginning with SQL Server 2008, you can use "composable DML" for more possibilities.
insert into YourTable values (...)
get the new PK with scope_identity()
select scope_identity()
INSERT INTO YourTable (1, 2, etc.)
OUTPUT inserted.yourIDcolumn
VALUES (value1, value2, value...)
Note: This is for MS SQL 2005 and greater
SCOPE_IDENTITY() is probably what you want. It returns the ID of the last record inserted by the same code context in which it executes.
IDENT_CURRENT('tablename') is subject to concurrency issues. That is, there's no guarantee that another record won't be inserted between the INSERT and the call to IDENT_CURRENT.
I must confess, I'm not sure to what source of amazement the VillageIdiot's outburst refers, but I myself am quite astonished that this question does not appear to be a duplicate at all.
holy crap!!!
just call SCOPE_IDENTITY() function:
insert into your_talble(col1,col2) values('blah','more blah')
select scope_identity()
because selecting highest value will return error if any other statement make an insert. the function scope_identity() returns the identity created in current context (that is by your statement)
You should use scope_identity(). And I recommend to wrap insert statement and scope_identity() into transaction.