Updating Identity Column of a table with consecutive numbers through SQL Stored Procedure - sql

After deleting the duplicate records from the table,
I want to update Identity column of a table with consecutive numbering starting with 1. Here is my table details
id(identity(1,1)),
EmployeeID(int),
Punch_Time(datetime),
Deviceid(int)
I need to perform this action through a stored procedure.
When i tried following statement in stored procedure
DECLARE #myVar int
SET #myVar = 0
set identity_insert TempTrans_Raw# ON
UPDATE TempTrans_Raw# SET #myvar = Id = #myVar + 1
set identity_insert TempTrans_Raw# off
gave error like...Cannot update identity column 'Id'
Anyone please suggest how to update Identity column of that table with consecutive numbering starting with 1.

--before running this make sure Foreign key constraints have been removed that reference the ID.
--insert everything into a temp table
SELECT (ColumnList) --except identity column
INTO #tmpYourTable
FROM yourTable
--clear your table
DELETE FROM yourTable
-- reseed identity
DBCC CHECKIDENT('table', RESEED, new reseed value)
--insert back all the values
INSERT INTO yourTable (ColumnList)
SELECT OtherCols FROM #tmpYourTable
--drop the temp table
DROP TABLE #tmpYourTable
GO

The IDENTITY keword is used to generate a key which can be used in combination with the PRIMARY KEY constraint to get a technical key. Such keys are technical, they are used to link table records. They should have no other meaning (such as a sort order). SQL Server does not guarantee the generated IDs to be consecutive. They do guarantee however that you get them in order. (So you might get 1, 2, 4, ..., but never 1, 4, 2, ...)
Here is the documentation for IDENTITY: https://msdn.microsoft.com/de-de/library/ms186775.aspx.
Personally I don't like it to be guaranteed that the generated IDs are in order. A technical ID is supposed to have no meaning other then offering a reference to a record. You can rely on the order, but if order is information you are interested in, you should store that information in my opinion (in form of a timestamp for example).
If you want to have a number telling you that a record is the fifth or sixteenth or whatever record in order, you can get always get that number on the fly using the ROW_NUMBER function. So there is no need to generate and store such consecutive value (which could also be quite troublesome when it comes to concurrent transactions on the table). Here is how to get that number:
select
row_number() over(order by id),
employeeid,
punch_time,
deviceid
from mytable;
Having said all this; it should never be necessary to change an ID. It is a sign for inappropriate table design, if you feel that need.

If you really need sequential numbers, may I suggest that you create a table ("OrderNumbers") with valid numbers, and then make you program pick one row from OrderNumbers when you add a row to yourTable.
If you everything in one transaction (i.e. with Begin Tran and Commit) then you can get one number for one row with no gabs.
You should have either Primary Keys or Unique Keys on both tables on this column to protect against duplicates.
HIH,
Henrik

Check this function: DBCC CHECKIDENT('table', RESEED, new reseed value)

Related

Increment number by one using an insert statement SQL

I am trying to manually add records to a SQL table
However in this table we have a column called Trackseq this column determines how the data is viewed on our CMS system.
The highest TrackSeq will appear first.
I want to manually add a new row but i want the code to check based on CLNTID what the current trackSeq is and add one to it. So if the trackseq of the last record was 10 I want the new record to go in with a trackseq of 11.
Here is my code.
INSERT INTO tbl_CommTracking ( CLNTID,
TRACKSEQ,
COMMDATE,
COMMTIME,
PRODCODE,
COMMTYPE,
EMPLOYEEID,
COMMDETAILS,
COMMSTATUS)
VALUES ('0000005566','999',GETDATE(),GETDATE(),'BS','Note','0000000786','Testing a manual import','A')
Thanks
Assuming TRACKSEQ is a numeric format, you can read the actual highest value and store it in a variable to use in your insert statement.
Please note that, in case of high concurrency, you may want to synchronize this execution in order to avoid duplicate #ts values.
As stated by #Tim Biegeleisen above, an IDENTITY column is best suited for this kind of tasks, but keep in mind that it may leave holes in number sequence in case of DELETE and failed INSERTS.
Eg:
DECLARE #ts int; --or whatever numeric datatype it is
SELECT #ts = MAX(TRACKSEQ) + 1 FROM tbl_CommTracking
INSERT INTO tbl_CommTracking (
--...
TRACKSEQ
--..
)
VALUES (
--...
#ts
--...
)
You should probably make TRACKSEQ an auto increment column. First drop your current TRACKSEQ column, then add it back:
ALTER TABLE tbl_CommTrackingDROP COLUMN TRACKSEQ;
ALTER TABLE tbl_CommTracking ADD TRACKSEQ INT IDENTITY;
Note that typically you would also make TRACKSEQ the primary key of the table. If you don't want to, that's OK, but then you'll have to make sure you can generate your own unique values for the CLNTID column.
It isn't entirely clear why you need this; if you just want the latest records, use the date/timestamp column available, which would have been set during insertion.

Inserting new rows and generate a new id based on the current last row

The primary key of my table is an Identity column of an ID. I want to be able to insert a new row and have it know what the last ID in the table currently is and add one to it. I know I can use Scope Identity to get the last inserted column from my code, but I am worried about people manually adding entries in the database, because they do this quite often. Is there a way I can look at the last ID in the table and not just the last ID my code inserted?
With a SQL Identity column, you don't need to do anything special. This is the default behavior. SQL Server will handle making sure you don't have collisions regardless of where the inserts come from.
The ##Identity will pull the latest identity, and scope_identity will grab the identity from the current scope.
A scope is a module: a stored procedure, trigger, function, or batch. Therefore, if two statements are in the same stored procedure, function, or batch, they are in the same scope.
If you don't want to allow manual entries to the primary column, then you can add Identity constraint to it along with primary key constraint.
Example, while creating a table,
CREATE Table t_Temp(RowID Int Primary Key Identity(1,1), Name Varchar(50))
INSERT Into t_Temp values ('UserName')
INSERT Into t_Temp values ('UserName1')
SELECT * from t_Temp
You can query the table and get the next available code in one SQL query:
SELECT COALESCE(MAX(CAST("RowID" AS INT)),0) +1 as 'NextRowID' from <tableName>
The "0" here is a default, meaning if there are no rows found, the first code returned would be (0+1) =1
Generally I have 999 instead of the 0 as I like my RowID/primary key etc. to start at 1000.

Primary key value after insertion of row in SQL Server 2005

In SQL Server 2005 I am inserting a row into a table using a stored procedure and I want to fetch the new primary key value just after inserting that row. I am using following approach to get primary key value after insertion row
Create Proc Sp_Test
#testEmail varchar(20)=null,-- Should be Unique
#testName varchar(20)=null -- Should be Unique
as
begin
insert into tableTest (testUserEmail,testUserName)values (#testValue,#testName)
select MAX(ID) from tableTest --ID is Primary Key
--or
select ID from tableTest where testUserEmail =#testValue and testUserName = #testName
--or
select SCOPE_IDENTITY() as ID
end
Please suggest me which approach is better to perform described task.
By all means - use the SCOPE_IDENTITY() if your ID column is an INT IDENTITY - only that will give you the correct results!
The first approach with the MAX(ID) will fail terribly if you have multiple clients inserting rows almost at the same time - you'll get false results back. Don't use that!
The third approach might fail if another entry with the same values for E-Mail and name already exists.
Also, as a side-note: you should never use sp_ as your prefix! This is a Microsoft-reserved prefix and has downsides in terms of performance - use something else.
If you have an Identity column as primary key you should use SCOPE_IDENTITY()
You could also use the OUTPUT Clause to return the ID.
insert into tableTest(testUserEmail,testUserName)
output inserted.ID
values (#testValue, #testName)

Inserting rows into a table with one IDENTITY column only [duplicate]

This question already has answers here:
How to insert into a table with just one IDENTITY column?
(5 answers)
Closed 1 year ago.
I have a table Administrator with only one column, adminId which is the primary-key. Because of business rules it has to be this way.
I'd like to understand once and for all how I can write stored procedures that insert values in tables like this. I am using SQL Server and T-SQL and tried using SCOPE_IDENTITY() but that doesn't work since the table has INSERT_IDENTITY to false or off.
I'd really like to not insert a dummy value just to be able to insert a new row. Thanks!
If you have one column that is an IDENTITY, just do this
INSERT MyTable DEFAULT VALUES; --allows no column list. The default will be the IDENTITY
SELECT SCOPE_IDENTITY();
If you don't have identity, then can you set it? This is the best way.. and use the SQL above.
If not, you want to insert a new row
INSERT MyTable (admidid)
OUTPUT INSERTED.admidid --returns result to caller
SELECT ISNULL(MAX(admidid), 0) + 1 FROM MyTable
Notes:
Under high loads the MAX solution may fail with duplicates
SCOPE_IDENTITY is after the fact, not before
SCOPE_IDENTITY only works with an IDENTITY column. Ditto any idiocy using IDENT_CURRENT
The output clause replaces SCOPE_IDENTITY for the MAX solution
You need to add the IDENTITY_INSERT to your select statement:
SET IDENTITY_INSERT MyTable ON
INSERT INTO MyTable
(AdminCol)
SELECT AdminColValue
FROM Tableb
When you're done, make sure you remember to
SET IDENTITY_INSERT MyTable OFF
Here's a good description of how it works from BOL: http://msdn.microsoft.com/en-us/library/aa259221(SQL.80).aspx
#Phil: Don't you mean your table has two(2) columns, the autoincrementing PK column and an AdminName column? If it only has one column where the AdminName goes, the AdminName is the PK and you cannot autoincrement a string, of course. Do the business rules expect you to make a fully-qualified Windows username the primary key? That would be viable and make sense, because then you wouldn't need an alternate unique index on the AdminName column.
But if your table has two columns, not one:
In SQLServer the autoincrement is part of the table/column definition. You define the column as an integer and then also make it an
identity column, specifying the increment, usually 1, but it could be 2 or 5 or 10 or whatever. To insert a row, you simply insert the other column(s) value(s) and do nothing with the PK column:
insert into T
(foo) -- column(s) list
values('bar') -- values list
Your stored proc that does the insert can make SCOPE_IDENTITY a RETURN value or SCOPE_IDENTITY can be passed back to the client as an OUT parameter.
P.S. SCOPE_IDENTITY() returns the most recently generated autoincremented identity value in the current scope; it does not generate the next identity value.
EDIT:
Presumably, your Administrators table contains a set of administrators. But if it has no columns whatsoever other than the integer primary key column, there is no way to identify the administators; the only thing you can do is distinguish them from each other. That doesn't get you very far at all. But if your Administrator table had either of the following structures:
ID INTEGER PRIMARY KEY AUTOINCREMENT
windowsusername varchar(50) (unique index)
OR
windowsusername varchar(50) primary key
you would be able to reference the Administrator's table from other tables, and the foreign keys would be MEANINGFUL. And that's precisely what a table consisting of a single integer column lacks -- meaning.
Having two columns, you could then have a stored procedure do this:
insert into Administrators
(windowsusername)
values('mydomain\someusername');
return SCOPE_IDENTITY();
and your client-program would get back as a return value the autoincremented id that had been autogenerated and assigned to the newly inserted row. This approach is the usual practice, and I would go so far as to say that it is considered "best practice".
P.S. You mention that you didn't know how to "insert a value" if you "didn't have anything to insert". There's a contradiction there. If you have nothing to insert, why insert? Why would you create, say, a new CUSTOMER record if you know absolutely nothing about the customer? Not their name, their city, their phone number, nothing?

Using ##IDENTITY in SQL on a specific table

How can I get the ##IDENTITY for a specific table?
I have been doing
select * from myTable
as I assume this sets the scope, from the same window SQL query window in SSMS I then run
select ##IDENTITY as identt
It returns identt as null which is not expected since myTable has many entrie in it already..
I expect it to return the next available ID integer.
myTable has a ID column set to Primary key and auto increment.
You can use IDENT_CURRENT
IDENT_CURRENT( 'table_name' )
Note that IDENT_CURRENT returns the last identity value for the table in any session and any scope. This means, that if another identity value was inserted after your identity value then you will not retrieve the identity value that you inserted.
You can only truly use SELECT ##IDENTITY after an insert - the last insert into a table that has an IDENTITY column is the value you'll get back.
You cannot "limit" it to a table - the value in ##IDENTITY - and by the way, I'd strongly recommend using SCOPE_IDENTITY() instead!! - is the last value on any IDENTITY column that was set.
The problem with ##IDENTITY is that it will report back the last IDENTITY value inserted into any table - if your INSERT into your data table will cause e.g. a trigger to write an entry into an Audit table and that Audit table has an IDENTITY field, you'll get back that IDENTITY value - not the one inserted into your table. SCOPE_IDENTITY() solves that.
IDENT_CURRENT does what you want. But don't.
This is in addition to marc_s' answer
I've never known ##IDENTITY to be used this way, i've only ever used it to access the ID of a newly inserted record.
That's correct. ##IDENTITY cannot be used the way you think it can be. It can only be used after an INSERT into a table. Let's consider this for a scenario:
You have two tables: Order (Primary Key: OrderID), OrderDetails (Foreign Key: OrderID)
You perform
INSERT INTO Order
VALUES('Pillows')
-- Note that OrderId is not mentioned in Values since it is auto number (primary key)
Now you want to perform insert into OrderDetail. But you don't always remember how many records there were in Order table prior to you having inserted the record for 'Pillows' and hence you don't remember what was the last PrimaryKey inserted into Order table. You could but even then you wouldn't want to specifically mention to insert (let's say OrderID of 1) when you insert into OrderDetail table.
Hence, your OderDetail insert would work kinda like so:
INSERT INTO OrderDetail
VALUES (##IDENTITY,'Soft Pillows')
Hope this explains the user of ##IDENTITY.