Programmatically set identity seed in a table variable - sql-server

I need to create a table variable with an identity seed that starts with the max value of a field in another table?
I've tried this:
DECLARE #IdentitySeed int
SET #IdentitySeed = (SELECT MAX(HHRecId) +1 FROM xxx )
DECLARE #HH TABLE (
HHId INT IDENTITY(#IdentitySeed,1)
,AddressType CHAR(1)
,Address1 VARCHAR(100)
,City VARCHAR(50)
,State VARCHAR(2)
,Zip VARCHAR(5)
,LastName VARCHAR(50)
)
But that gives a syntax error.
For now, I've added another int column to the table variable and update that with the sum of the identity column and #IdentitySeed but I would like to find a way to do that without the update.

You can check the current value of an IDENTITY column by using:
DBCC CHECKIDENT (#HH)
and you can also change that later on using:
DBCC CHECKIDENT (#HH, RESEED, 42)
and that also works with a variable for the new value:
DBCC CHECKIDENT (#HH, RESEED, #IdentitySeed)
It works for local and global temporary tables (i.e. CREATE TABLE #HH (...) or CREATE TABLE ##HH (....) - but it doesn't seem to work with table variables :-(
Sorry, it seems you can't do this with table variables.....

I ended up doing the following:
DECLARE #NewId INT
SELECT #NewId = MAX(ID) FROM MyIDSTable
DECLARE #MyTempData TABLE (
Id int not null primary key
,Field1 int not null
,Field2 nvarchar(25) not null
,Field3 datetime
)
INSERT INTO #MyTempData
SELECT ROW_NUMBER() OVER ( Order by [C].[Cancel_id] ASC) + #NewId -1 [RowNum]
,Field1
,Field2
,Field3
INSERT INTO MyTable SELECT * FROM #MyTempData
UPDATE MYIDSTable SET ID = (SELECT MAX(ID) FROM #MyTempData) + 1 WHERE Name = 'Something'
Thank you

I believe you can do this, but it'll have to be done in dynamic SQL - declare the tableVar in the dynamic SQL and use it there too!
It would surely be easier and result in faster code if you started it at 1 and had a secondary ID field that is calculated as MAX(HHRecId) + ID.

Related

Capture IDENTITY column value during insert and use as value for another column in same transaction

While performing an insert to a table which has an IDENTITY column, is it possible to use the IDENTITY value as the value for another column, in the same transaction?
For example:
DECLARE #TestTable TABLE
(
PrimaryId INT NOT NULL IDENTITY(1, 1),
SecondaryId INT NOT NULL
);
INSERT INTO #TestTable (SecondaryId)
SELECT
SCOPE_IDENTITY() + 1; -- set SecondaryId = PrimaryId + 1
SELECT * FROM #TestTable;
Expected:
| PrimaryId | SecondaryId |
+-----------+-------------+
| 1 | 2 |
I thought I might be able to achieve this with the SCOPE_IDENTITYor ##IDENTITY system functions, but unfortunately this does not work, as it is NULL at the time the transaction is executed.
Cannot insert the value NULL into column 'SecondaryId', table '#TestTable'; column does not allow nulls. INSERT fails.
I know I could use a computed column for this example, but I'm curious if what I'm trying to do is even possible.
Could you change your approach and use a SEQUENCE instead of an IDENTITY column?
CREATE SEQUENCE TestSequence
START WITH 1
INCREMENT BY 1 ;
GO
CREATE TABLE TestTable (PrimaryId INT NOT NULL DEFAULT NEXT VALUE FOR TestSequence, SecondaryId INT NOT NULL);
GO
INSERT INTO TestTable (
SecondaryId
)
SELECT NEXT VALUE FOR TestSequence + 1; -- set SecondaryId = PrimaryId + 1;
GO 3
SELECT * FROM TestTable;
GO
DROP TABLE TestTable;
DROP SEQUENCE TestSequence;
I would go with a trigger, this should also work for multi row inserts, You will need to remove the not null for SecondaryID, not sure if that's acceptable.
create trigger trg_TestTable
on dbo.TestTable
after insert
AS
BEGIN
update TestTable
set SecondaryId = i.PrimaryId
from inserted i
join TestTable a
on i.PrimaryId = a.PrimaryId;
END
GO
One thing you could do is use the OUTPUT INSERTED option of the INSERT COMMAND to capture the IDENTITY.
In this example the IDENTITY field is ScheduleID.
CREATE PROCEDURE dbo.spScheduleInsert
( #CustomerID int,
#ItemID int,
#StartDate Date,
#TimeIn DateTime,
#TimeOut DateTime,
#ReturnIdentityValue int OUTPUT )
AS
BEGIN
DECLARE #TempScheduleIdentity table ( TempScheduleID int )
INSERT INTO Schedule ( CustomerID,ItemID,StartDate,TimeIn,TimeOut )
OUTPUT INSERTED.ScheduleID into #TempScheduleIdentity
VALUES (#CustomerID,#ItemID,#StartDate,#TimeIn,#TimeOut)
SELECT #ReturnIdentityValue = (SELECT TempScheduleID FROM #TempScheduleIdentity)
END
Once you have the #ReturnIdentityValue...you could then update the records other field with the value.

Deleting records from SQL Server but not resetting PK

I deleted all records from a table on a SQL Server 2014 using the TRUNCATE function, but now new records on this table begin with PK 1.
Is there a way to not reset the primary key so that the new records begin from the last PK + 1?
Deleting will work. But sometimes the time a delete takes can be an issue. If you have to truncate you can do the following:
Get the maximum value from your table and store this in a variable.
Truncate the table
Reseed the identity to the variable value + 1.
Here is an example.
DECLARE #MaxID AS INT;
SELECT #MaxID = MAX(ID) + 1
FROM TableA;
TRUNCATE TABLE TableA;
DBCC CHECKIDENT ('dbo.TableA', RESEED, #MaxID);
New inserts into the table will now continue from the previous identity value.
Marius
Using DELETE seems to work.
DECLARE #Tab TABLE (Id INT IDENTITY(1,1), Col VARCHAR)
DECLARE #Num INT = 10,
#Count INT = 0
WHILE #Count < #Num
BEGIN
INSERT #Tab
VALUES('')
SET #Count = #Count + 1
END
DELETE FROM #Tab
INSERT #Tab
VALUES ('')
SELECT *
FROM #Tab

SQL need to insert into table which only consists of a primary key but no auto increment

I need to insert a value into a table which only consists of one column, that is, the primary key.
Furthermore, NULL is not allowed, Identity is set to FALSE and both Identity Seed and Identity Increment are set to 0.
I try to insert with INSERT INTO table(id) VALUES (null) which obviously does not work. INSERT INTO table(id) default values also does not work.
How can I fill this column with the correctly incremented ID?
Implementing Identity or Sequence would be the best solution, but if you really cannot alter the schema the alternative is to lock the table in a transaction, create the new value, unlock the table. Note this can have performance consequences.
create table dbo.ids ( id int primary key clustered );
GO
insert dbo.ids values ( 1 ), ( 2 ), ( 3 ), ( 4 ) ;
GO
declare #newid int;
begin transaction
set #newid = ( select top( 1 ) id from dbo.ids with ( tablockx, holdlock ) order by id desc ) + 1 ;
insert into dbo.ids values ( #newid );
select #newid;
commit
GO 20
You can use while function in that insert
declare #id int
select #id = max(id) from table
while #id <= (... put here max nuber of your id you want to insert)
begin
insert into table values (#id)
set #id = #id+1 end
end
This can be a solution too.
declare #newid integer
begin tran
select #newid = isnull(max(id), 0) + 1 from table with (xlock,holdlock)
insert into table values(#newid)
select #newid
commit tran

How to insert values in to 2 tables, where the 2nd table need an Id from the 1st table?

I have an ordering system where when a new order is placed it is inserted into my table Orders. From there I want to insert the new id into another table Importance which also needs an id from a third table called ImportanceRating.
Table structures:
Order
OrderId uniqueidentifier
TimeOrderPlaced datetime
ProductId uniqueidentifier
EstimatedDeliveryTime datetime
Importance
FK_OrderId uniqueidentifier
FK_ImpRatingId uniqueidentifier
ImportanceRating
ImpRatingId uniqueidentifier
RatingTitle varchar(50)
All of this I want merged in 1 stored procedure. How would I go about with this?
Links to good guides on the subject is more than welcome.
I'm a SPROC newbie
Could you try this?:
CREATE PROCEDURE AddOrderAndRatingSample
-- These are the values you want to insert
#paramTimeOrderPlaced DATETIME
, #paramProductId INT
, #paramEstimatedDeliveryTime DATETIME
, #paramRatingTitle VARCHAR(50)
AS
BEGIN
DECLARE #siOrderId INT
DECLARE #siImpRatingId INT
-- Assuming that `OrderId` in table `Order` is an `identity column`:
INSERT INTO Order (TimeOrderPlaced, ProductId, EstimatedDeliveryTime)
VALUES(#paramTimeOrderPlaced, #paramProductId, #paramEstimatedDeliveryTime)
SET #siOrderId = SCOPE_IDENTITY()
-- Assuming `ImpRatingId` in table `ImportanceRating` is an `identity column`:
INSERT INTO ImportanceRating (RatingTitle)
VALUES(#paramRatingTitle)
SET #siImpRatingId = SCOPE_IDENTITY()
-- And that both `FK_OrderId` and `FK_ImpRatingId`
-- in table `Importance` are not `identity columns`:
INSERT INTO Importance (FK_OrderId, FK_ImpRatingId)
SELECT #siOrderId, #siImpRatingId
END
Could you please try this way:
DECLARE #OrderId INT
INSERT INTO Order (TimeOrderPlaced, ProductId, EstimatedDeliveryTime)
VALUES(#paramTimeOrderPlaced, #paramProductId, #paramEstimatedDeliveryTime)
SET #OrderId = ##IDENTITY -- Last orderId
INSERT INTO ImportanceRating (RatingTitle)
VALUES(#paramRatingTitle)
INSERT INTO Importance (FK_OrderId, FK_ImpRatingId)
SELECT #OrderId, ##IDENTITY -- Here ##IDENTITY returns last ID of ImportanceRating
-- Each inserting time the global variable ##IDENTITY is set with last IDENTITY value

Is there anyway to reset the identity of a Table Variable?

Say I have a table variable:
DECLARE #MyTableVar TABLE (ID INT IDENTITY(1,1), SomeData NVARCHAR(300))
After I have inserted 250 rows, I need to "Start Over" with the table. I do this:
DELETE FROM #MyTableVar
Is there anything I can do to the table variable so that this:
insert into #MyTableVar Values("TestData")
select * from #MyTableVar
will return this:
_______________________________
| ID | SomeData |
|___________|_________________|
| | |
| 1 | TestData |
|___________|_________________|
instead of this:
_______________________________
| ID | SomeData |
|___________|_________________|
| | |
| 251 | TestData |
|___________|_________________|
Instead relying on an Identity, why not use the new ranking functions such as Row_Number
Insert #MyTableVar( Id, Value )
Select Row_Number() Over ( Order By Value )
, Value
From SomeOtherTable
Instead of re-seeding the IDENTITY, why not just delete from the #table variable, then use ROW_NUMBER() against the input? e.g. instead of the lazy
SELECT * FROM #MyTableVar;
...use...
SELECT ID = ROW_NUMBER() OVER (ORDER BY ID), SomeData FROM #MyTableVar;
Now you don't need to care what the seed is, whether it starts at 1, whether there are any gaps, etc.
unfortunately there is no function to reseed identity column in table variable, I know this question is very old, but in case other people encountered the same problem, I would like to share my method to solve this problem.
/* declare another table variable with same structure and perform select insert*/
DECLARE #MyTableVar1 TABLE (ID INT IDENTITY(1,1), SomeData NVARCHAR(300))
insert into #MyTableVar1
select someData from #MyTableVar
However, If you want to perform dynamic reseeding inside a loop, I would suggest using a table object
You can't reseed the identity value on a Table Variable but you can do the same thing with a Temp Table:
CREATE TABLE #TAB(ID INT IDENTITY,VALUE VARCHAR(10))
DECLARE #RESEED INT = 32
DBCC CHECKIDENT(#TAB,RESEED,#RESEED)
INSERT INTO #TAB
SELECT 'TEST'
SELECT * FROM #TAB
Since you are re-using your table, if I got it right, how about you do not initialize your counters to 1 and instead use this as an example?
DECLARE #ctr INT
IF #ctr IS NULL or #ctr <= 0 --this part is to control #ctr value on loops
SET #ctr = 1
ELSE
SELECT #ctr = MIN(id) FROM #tbl
This way, you are not restarting your loop to 1 nor is there a need for you to truncate the table.
Is it possible to have another int column on your table variable and update that column with modulo after the insert is finished?
declare #Mytablevar table
(
id int identity(1,1)
,id1 int
somedata nvarchar(300)
)
-- insert your data as you would. After insert is finished, do the following:
update #mytablevar set id1 = case when id > 250 then id % 250 else id end
I tried it on net but i am not able to get any solution on reset identity for table variable.
If you are able to use temp table #MyTableVar instead of table #MyTableVar variable then it is possible to reset identity value
DBCC CHECKIDENT('TableName', RESEED, NewValue)
DBCC CHECKIDENT(#MyTableVar, RESEED, 0)
Newvalue must be one less than the newIdentiyValue
NewValue= NewIdentity-1;
If you still want to learn more you can refer my blog
http://tryconcepts.blogspot.in/2012/08/reset-identity-column-to-new-id.html
I just had this idea and it works!!! :
declare #TableVariable table (
IdentityColumn int identity(1,1),
SomeOtherValue int,
DesiredResult int
)
declare #FirstIdentityValueEachTimeYouLoadDataToTable int
declare #Count int
set #Count = 1
while #Count <= 5
begin
delete #TableVariable
insert into #TableVariable (SomeOtherValue) select 45
insert into #TableVariable (SomeOtherValue) select 90
insert into #TableVariable (SomeOtherValue) select 2
select #FirstIdentityValueEachTimeYouLoadDataToTable = min(IdentityColumn) from #TableVariable
Update #TableVariable set DesiredResult = IdentityColumn - #FirstIdentityValueEachTimeYouLoadDataToTable + 1
select * from #TableVariable
set #Count = #Count + 1
end
Can you use temporary table?
This is a sample how to do this with a temp table.
CREATE TABLE #MyTableVar (ID INT IDENTITY(1,1), SomeData NVARCHAR(300))
insert #MyTableVar(SomeData) values ('test1'), ('test2')
---doesn't work
DELETE FROM #MyTableVar
insert #MyTableVar(SomeData) values ('test3'), ('test4')
select * from #MyTableVar
--resets the identity
truncate table #MyTableVar
insert #MyTableVar(SomeData) values ('test3'), ('test4')
select * from #MyTableVar
Regards
Piotr
you should truncate your table instead of deleting all rows from it.
but note that truncate will not work for some tables, (listed from MSDN):
You cannot use TRUNCATE TABLE on tables that:
Are referenced by a FOREIGN KEY constraint. (You can truncate a table that has a foreign key that references itself.)
Participate in an indexed view.
Are published by using transactional replication or merge replication.
and added myself:
You cannot truncate a table variable.
syntac of truncate is:
TRUNCATE TABLE
[ { database_name .[ schema_name ] . | schema_name . } ]
table_name
[ ; ]
EDIT: I didn't notice that you are questioning about table variables.
as far as I know there is no way to reset an identity column in a table variable. you can use a temp table instead.
DELETE FROM does not reset identity.
TRUNCATE does.
If you are using SQL Server then use this DBCC CHECKIDENT('Customer', RESEED, 0) Where Customer is a table name. When you insert records into table after this command your primery key column value will be start from 1 again.
Read this
http://codedotnets.blogspot.in/2012/09/how-to-reset-identity-in-sql-server.html

Resources