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
Related
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.
I can use the OUTPUT keyword of the insert statement to insert new data to a table and output to a temporary table.
The input table which to be inserted into another table have an Id I need to pass to the temporary table but not the table I going to insert into. This temporary table will later have to use to do extra insertion to the other table.
INSERT INTO table1 (Name, Age)
OUTPUT inserted.Id, User.Id (??) INTO TemporaryTable
SELECT Name, Age FROM User
Is there a way to do it? Because the next insertion will need the new table1.Id with the User.Id, so I can migrate some data.
Instead of using the Temporary table you can use Variable so that it will not occupy more memory.
create table table1
(
id int NOT NULL,
,name varchar(50)
,age int,
PRIMARY KEY (id)
)
insert into table1 (name,age) values ('name', 10)
declare #extracolumn as int = scope_identity()
select #extracolumn
use this #extracolumn in next insert operation.
Have you included the extra column in the schema of the temporary table?
create table table1
(
id int
,name varchar(50)
,age int
)
declare #TemporaryTable table -- or Create table #TemporaryTable
(
id int,
userid int -- defining the extra column
);
declare #extracolumn as int = 100;
-- or declare #extracolumn as int = (select value from table where condition)
-- note that subqueries cannot be added directly in the output clause
-- so need to declare and set a variable that holds the value
insert into table1
output inserted.id,#extracolumn into #TemporaryTable -- or #TemporaryTable
values(1,'name',10)
select * from #TemporaryTable
Output is
id userid
1 100
I have table holding items for a given list id in my Ms Sql server database (2008R2).
I would like to add constraints so that no two list ids have same item list. Below illustrate my schema.
ListID , ItemID
1 a
1 b
2 a
3 a
3 b
In above example ListID 3 should fail. I guess you can't put constarint/check within the database itself (Triggers,check) and the logic constaint can only be done from the frontend?
Thanks in advance for any help.
Create a function that performs the logic you want and then create a check constraint or index that leverages that function.
Here is a functional example, the final insert fails. The function is evaluated row by row, so if you need to insert as a set and evaluate after, you'd need to do an "instead of" trigger:
CREATE TABLE dbo.Test(ListID INT, ItemID CHAR(1))
GO
CREATE FUNCTION dbo.TestConstraintPassed(#ListID INT, #ItemID CHAR(1))
RETURNS TINYINT
AS
BEGIN
DECLARE #retVal TINYINT = 0;
DECLARE #data TABLE (ListID INT, ItemID CHAR(1),[Match] INT)
INSERT INTO #data(ListID,ItemID,[Match]) SELECT ListID,ItemID,-1 AS [Match] FROM dbo.Test
UPDATE #data
SET [Match]=1
WHERE ItemID IN (SELECT ItemID FROM #data WHERE ListID=#ListID)
DECLARE #MatchCount INT
SELECT #MatchCount=SUM([Match]) FROM #data WHERE ListID=#ListID
IF NOT EXISTS(
SELECT *
FROM (
SELECT ListID,SUM([Match]) AS [MatchCount]
FROM #data
WHERE ListID<>#ListID
GROUP BY ListID
) dat
WHERE #MatchCount=[MatchCount]
)
BEGIN
SET #retVal=1;
END
RETURN #retVal;
END
GO
ALTER TABLE dbo.Test
ADD CONSTRAINT chkTest
CHECK (dbo.TestConstraintPassed(ListID, ItemID) = 1);
GO
INSERT INTO dbo.Test(ListID,ItemID) SELECT 1,'a'
INSERT INTO dbo.Test(ListID,ItemID) SELECT 1,'b'
INSERT INTO dbo.Test(ListID,ItemID) SELECT 2,'a'
INSERT INTO dbo.Test(ListID,ItemID) SELECT 2,'b'
Related
I have a condition like this:
IF #aaa = 'high'
set #bbb = select * from table1
else
set #bbb = select * from table2
I am going to use this variable (#bbb) throughout my stored procedure
is this possible to save a table into a variable?
I tried using temporary table but i am not able to assign it twice.
IF #aaa = 'high'
set #bbb = select * into #temp from table1
else
set #bbb = select * into #temp from table2
it shows #temp is already declared.
No, It is not work like that. You can declare a table variable and insert into inside it.
DECLARE #bbbTable TABLE(
Id int NOT NULL,
SampleColumn varchar(50) NOT NULL
);
insert into #bbbTable (Id,SampleColumn)
select Id,SampleColumn from table1
If the table1 and table2 are completely different tables, you should declare two different table variable;
DECLARE #bbbTable TABLE(
Id int NOT NULL,
SampleColumn varchar(50) NOT NULL
);
DECLARE #aaaTable TABLE(
Id int NOT NULL,
SampleColumn varchar(50) NOT NULL
);
IF #aaa = 'high'
insert into #bbbTable (Id,SampleColumn)
select Id,SampleColumn from table1
else
insert into #aaaTable (Id,SampleColumn)
select Id,SampleColumn from table2
You cant insert into a variable more than 1 value.
you can use Table Variable to reach your answer like this:
DELCARE #TableResult AS TABLE (Column1 INT, Column2 INT)
IF #aaa = 'high'
BEGIN
INSERT INTO #TableResult (Column1,Column2)
SELECT Column1FromTable, Column2FromTable
FROM table1
END
ELSE
BEGIN
INSERT INTO #TableResult (Column1,Column2)
SELECT Column1FromTable, Column2FromTable
FROM table2
END
Of course you can declare more than 2 columns.
You can store only 1 Column/Row to a variable.So you can't say *.
Suppose I want to store the value of Column1 from TableA to a variable, I can use this
SELECT #MyVariable = Column1 FROM TableA
But I Can't Say
SELECT #MyVariable = * FROM TableA
Even if there is only 1 column in the Table TableA.
Also If there is more than 1 record returned by the Select condition, then it will assign the First value to the Variable.
Or What you need is to store the entire Rows, you can Either use a Temporary table or a table variable.
Temporary Table
SELECT * INTO #Temp FROM TableA
Table Variable
DECLARE #MyVarTable TABLE
(
Column1 VARCHAR(50),
Column2 VARCHAR(50)
)
INSERT INTO #MyVarTable
(
Column1 ,
Column2
)
SELECT
Column1 ,
Column2
From MyTable
This Temporary Table and Table variable can be accessed in the same way you access the normal table using SELECT/UPDATE/DELETE Queries. Except :
Temporary tables are created for each session and automatically dropped when the session ends or the Query window is Closed
Table Variables exists only when you execute the Query. So before using the table variable in a query you need to declare the same
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.