Changing primary key value for a database row - sql

I am using SQL Server Management Studio and I want to change an auto increment primary key value of a table row, with a different value. SQL Server Management Studio after opening the table for edit, shows this field grayed for all rows, of course.
Is it possible? I want to use the number of a row we deleted by mistake, therefore it's valid (there is no conflict with other primary key values) and - most important of all - the next row added in the DB should have an intact auto incremented value.
Thanks.
EDIT: losing the link with other table records on this PK is not an issue for this row. We can restore it manually.

Not necessarily recommended but, insert a copy of the row where you want to change the number, but with the ID you require:
SET IDENTITY_INSERT aTable ON
GO
-- Attempt to insert an explicit ID value of 3
INSERT INTO aTable (id, product) VALUES(3, 'blah')
GO
SET IDENTITY_INSERT aTable OFF
GO
Then delete the row with the number you don't want (after you update any FK references).
More details here: http://technet.microsoft.com/en-us/library/aa259221(v=sql.80).aspx
For posterity, to clarify the question in the comment below, the auto increment value will only be affected if you insert a value greater than the current maximum.
Quoting from linked article:
If the value inserted is larger than the current identity value for
the table, SQL Server automatically uses the new inserted value as the
current identity value.

Related

INSERT with autoincrement not working in SQL Server (with DB replication ?)

After no row deletion, but after getting the 60 existing rows by local subscription to replication from another SQL Server instance, I'm inserting new rows with:
INSERT INTO [Business].[dbo].[ImagesTable] (Filename, Title, Price, PriceString, Category, CategoryRank)
VALUES ('vegan1.jpg', 'vegan1', 380000, '380,000', 'delices vegan', 0)
But this will fail since the ID will start over somewhere (9 in this case), instead of starting at the last ID used +1, ie., 61 in my case.
System.Data.SqlClient.SqlException: 'Violation of PRIMARY KEY constraint 'PK_ImagesTable'. Cannot insert duplicate key in object 'dbo.ImagesTable'. The duplicate key value is (9).
My table is set to have autoincrement, therefore I should not have to use explicit IDENT_CURRENT('ImagesTable'). Why is this happening ?
Furthermore and despite this, when I try to insert explicitly ID I have:
Cannot insert explicit value for identity column in table 'ImagesTable' when IDENTITY_INSERT is set to OFF.
What is the recommended way to add new rows? How can I insert new rows with the ID being automatically set?
If the presence of DB replication is not propagating the Identity seed, how should I deal with this so I don't have to manage duplicate key errors (I'm certain that I'm not inserting duplicates)?
You need to segment your IDENTITY column ranges in bidirectional replication.
https://learn.microsoft.com/en-us/sql/relational-databases/replication/publish/replicate-identity-columns?view=sql-server-ver15

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.

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

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)

Sql Server - How to get last id inserted into table

I'm trying to get the last id inserted into a table.
I was using
SELECT IDENT_CURRENT('TABLE')
But the problem is that it doesn't return the last inserted id, it returns the max inserted id.
For example, if i do:
INSERT INTO 'TABLA' (ID) VALUES (100)
SELECT IDENT_CURRENT('TABLE') returns 100
but then if i do
INSERT INTO 'TABLA' (ID) VALUES (50)
SELECT IDENT_CURRENT('TABLE') returns 100
and I want to get 50
I need the ID of a specific table, and I generate the id dinamically, so it's not an identity
How can i do it?
From your code, it looks like ID is not an identity (auto-increment) column, so IDENT_CURRENT isn't going to do what you are expecting.
If you want to find the last row inserted, you will need a datetime column that represents the insert time, and then you can do something like:
SELECT TOP 1 [ID] FROM TABLEA ORDER BY [InsertedDate] DESC
Edited: a few additional notes:
Your InsertedDate column should have a default set to GetDate() unless your application, stored procs or whatever you use to perform inserts will be responsible for setting the value
The reason I said your ID is not an identity/auto-increment is because you are inserting a value into it. This is only possible if you turn identity insert off.
SQL Server does not keep track of the last value inserted into an IDENTITY column, particularly when you use SET IDENTITY_INSERT ON;. But if you are manually specifying the value you are inserting, you don't need SQL Server to tell you what it is. You already know what it is, because you just specified it explicitly in the INSERT statement.
If you can't get your code to keep track of the value it just inserted, and can't change the table to have a DateInserted column with a default of CURRENT_TIMESTAMP (which would allow you to see which row was inserted last), perhaps you could add a trigger to the table that logs all inserts.
SELECT SCOPE_IDENTITY()
will return the last value inserted in current session.
Edit
Then what you are doing is the best way to go just make sure that the ID Column is an IDENTITY Column, IDENT_CURRENT('Table_name'), ##IDENTITY and SCOPE_IDENTITY() returns last value generated by the Identity column.
If the ID column is not an Identity Column, all of these functions will return NULL.

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.