I am stuck with this seemingly simple issue.
I have a sql server 2008 table tblCabinet with CabinetID as Primary Key and Identity (Seed=1)
Now i insert into and delete from this table. So now when i enter a new row into tbl insert
Insert into tblCabinet values ('F',5,5,5)
It enters a new row with Cabinet ID of 11. I know it has happened because i have deleted the rows in between .
How do i ensure it takes the next available identity, in this case Cabinet ID of 4 by still keeping identity insert ON ? i know i can enter manually by inserting MAX (CabinetID) +1.
You can reset the seed permanently like this:
declare #max int;
select #max = max(key) from table;
dbcc checkident(table,reseed,#max)
but really there isn't any nice way to do this I know of.
you need to set Primary Key and Identity off and have to calculate it manually.
your insert query will look like
Insert into tblCabinet
values (Select MAX (CabinetID) +1 FROM tblCabinet ,'F',5,5,5)
Related
I support a data replication product. I have a client who is very frustrated that SQL Server can't have a table with an Identity column that BOTH increments automatically when a row is added without providing a value for that column, and at the same time will accept/use a value when it is provided - and I might add, with both of those things happening continuously at a high rate and across hundreds of tables. They point to other databases that apparently can do this.
Everything I see online and my own experimentation seems to indicate that this simply can't be done in SQL Server, but I wanted to put it out there in case I'm just wrong and missing something. My only advice to them so far has been to switch to a Sequence (instead of Identity) and use it as a default value for the column. I've tested that and it works perfectly like they would want, but they are groaning at the idea of doing that for hundreds of tables. Thanks.
The point of an IDENTITY is that SQL Server is in control of it; you let SQL Server manage the value completely. What you really want is a SEQUENCE as a DEFAULT value.
CREATE TABLE dbo.SomeTable (ID int NOT NULL,
SomeColumn varchar(10));
GO
CREATE SEQUENCE dbo.SomeTableID START WITH 1 INCREMENT BY 1;
GO
ALTER TABLE dbo.SomeTable ADD CONSTRAINT PK_SomeTable PRIMARY KEY CLUSTERED (ID);
ALTER TABLE dbo.SomeTable ADD CONSTRAINT DF_SomeTableID DEFAULT NEXT VALUE FOR dbo.SomeTableID FOR ID;
GO
INSERT INTO dbo.SomeTable (SomeColumn)
VALUES ('abc'),('def');
GO
INSERT INTO dbo.SomeTable(ID,SomeColumn)
VALUES(3,'xyz');
GO
--Errors due to 3 already in use, but intended.
INSERT INTO dbo.SomeTable (SomeColumn)
VALUES ('abc');
GO
INSERT INTO dbo.SomeTable (SomeColumn)
VALUES ('def'); --4
GO
--Cleanup
DROP TABLE dbo.SomeTable;
DROP SEQUENCE dbo.SomeTableID;
db<>fiddle
I have the following table:
create table testTable
(
id int identity primary key,
string varchar(256),
constraint testConstraint unique(string)
)
with the following trigger:
create trigger testTrigger
on testTable
for delete as
begin
declare #max_ int
select #max_= max(id) from testTable
if #max_ is null
set #max_ = 0
DBCC CHECKIDENT ('testTable', RESEED, #max_)
end
Executing the following commands:
insert into testTable(string) values ('test') --identity = 1
insert into testTable(string) values ('test') --error thrown because duplicate key but **identity = 2**
insert into testTable(string) values ('test1') --due to erroneous identity increment identity = 3
The first insertion sets identity = 1, the second throws an error because of unique(string) constraint but identity is erroneous set to 2.
The question is how do I make it so that errors do not increment identity?
Is there a do-all be-all feature of SQL Server where the identity is ensured to be produced in a sequential fashion based on what's already in the column/table? Thus all edge cases such as this will be captured.
Thanks in advance (:
As others have mentioned, don't worry about gaps in the identity column coming from DELETEs.
If you absolutely need an increment number with no gaps in it, you could handle that on the SELECT side when needed.
For example, see ROW_NUMBER ... this can be used along with sorting on a timestamp column of your linking (something like SYSUTCDATETIME) to get the exact sequence of addition for rows, ORDER DESC, with ROW_NUMBER() in the query.
This will NOT be tied to the data, because if rows are DELETEd, these ROW_NUMBERS will change.
There shouldn't be any need to prevent gaps in an identity column. It sounds like you might be applying business logic to a surrogate key, which kind of defeats the purpose. You could do a sequence as Sean Lange points out in the comments.
In SQL Server, I have created a Table with an ID column that I have made an IDENTITY COLUMN,
EmployeeID int NOT NULL IDENTITY(100,10) PRIMARY KEY
It is my understanding, when I use the IDENTITY feature, it auto increments the EmployeeID. What I don't know/not sure is:
Is that IDENTITY number created, unique?
Does SQL search the entire column in the table to confirm the number created does not already exist?
Can I override that auto increment number manually?
If I did manually override that number, would the number I enter be checked to make sure it is not a duplicate/existing ID number?
Thanks for any help provided.
Is that IDENTITY number created, unique?
Yes, Identity property is unique
Does SQL search the entire column in the table to confirm the number created does not already exist? \
It need not, what this property does is, just incrementing the old value
Can I override that auto increment number manually?
Yes, you can. You have to use SET IDENTITY_INSERT TABLENAME ON
If I did manually override that number, would the number I enter be checked to make sure it is not a duplicate/existing ID number?
No, that won't be taken care by SQL Server, you will have to ensure you have constraints to take care of this
Below is a simple demo to prove that
create table #temp
(
id int identity(1,1)
)
insert into #temp
default values
go 3
select * from #temp--now id column has 3
set identity_insert #temp on
insert into #temp (id)
values(4)
set identity_insert #temp off
select * from #temp--now id column has 4
insert into #temp
default values
go
select * from #temp--now id column has 5,next value from the last highest
Updating info from comments:
Identity column will allow gaps once you reseed them,also you can't update them
I've already read the following answers about the impossibility to alter a column into identity once has been created as a regular int.
Adding an identity to an existing column
How to Alter a table for Identity Specification is identity SQL Server
How to alter column to identity(1,1)
But the thing is I have a table which has been migrated to a new one where the ID was not declared as identity from the beginning, because the old table which was created with an ID identity a long time ago has missing rows due to a purge of historical data. So as far as I know, if I add a new column as identity on my new table, it will automatically create the column sequentially and I need to preserve the IDs from the old table as-is because there is already data linked to these previous IDs.
How can I do transform my ID column from the new table as identity but not sequentially, but with the IDs from the old table?
You could try this approach:
Insert rows with old ID with SET IDENTITY_INSERT <new table> ON. This allows you to insert your own ID.
Reseed the Identity, setting it to the highest ID value +1 with DBCC CHECKIDENT ('<new table>', RESEED, <max ID + 1>). This will allow your Identity to increase from the highest ID and forward.
Something like this in code:
-- Disable auto increment
SET IDENTITY_INSERT <new table> ON
-- <INSERT STUFF HERE>
SET IDENTITY_INSERT <new table> OFF
-- Reseed Identity from max ID
DECLARE #maxval Int
SET #maxval = ISNULL(
(
SELECT
MAX(<identity column>) + 1
FROM <new table>
), 0)
DBCC CHECKIDENT ('<new table>', RESEED, #maxval)
EDIT: This approach requires your ID-column to be an Identity, of course.
If you don't have nulls in the field that you want to copy over from your previous version, you could first figure out what the largest ID is by just doing a max(Id) select. Then using SSMS go add your new field and when you set it as identity, just set the SEED value to something higher than what your current max is so you don't have collisions on new inserts.
I have a process where a temp table is used between a source file, CSV and the production table. The temp table has to match the CSV file columns, there is no PK in this data.
To find a set of rows before and after where the Azure Data Factory was failing, I imported over 2,000,000 rows into a temp table. The process stopped in Azure at 1,500,000 rows.
The error was that an integer or string would be truncated.
This line of code added a PK to the temp table and incremented it:
ALTER TABLE ##FLATFILETEMPBDI ADD ROWNUM INT IDENTITY
That would be the simplest solution to get a row number. I was then able to do this query to find the rows just before and after 1,500,000:
SELECT
ROWNUM
, PARTDESCRIPTION
, LEN(PARTDESCRIPTION) AS LENDESCR
, QUANTITY
, ONORDER
, PRICE
, MANUFACTURERPARTNUMBER
FROM ##FLATFILETEMPBDI
WHERE ROWNUM BETWEEN 1499990 AND 1500005
Works perfectly -- was not planning on it to be that easy, was surprised as anyone to see that the ALTER TABLE with IDENTITY worked to do the numbering for me.
I'm using SQL Server 2008
as per microsoft, http://msdn.microsoft.com/en-us/library/ms188059.aspx
when I execute the following
set identity_insert on
//insert statements here
set identity_insert off
the identity of the column is set to the maximum value. Can I avoid this?
Consider the following scenario,
my table has 2 rows as follows
id, name comm
1, John, 232.43
2, Alex, 353.52
now using the above code, when I insert
10, Smith, 334.23
as per the above link, SQL Server automatically sets the identity to 10. So for newly inserted records (without using identity_insert on), id automatically starts with 11.
I want the identity value to be 3, after using identity_insert on/off
please help.
Here's a test table for this discussion
create table t4721736 ( id int identity primary key, name varchar(10), comm money )
insert t4721736 select 'John', 232.43 -- id=1
insert t4721736 select 'Alex', 353.52 -- id=2
-- check contents
select * from t4721736
-- do all this in a transaction
BEGIN TRAN
-- dummy insert
insert t4721736 select 'dummy', null
-- get what the id should be
declare #resetto bigint
set #resetto = scope_identity()
-- remove dummy record
delete t4721736 where id = #resetto
-- perform the insert(s)
set identity_insert t4721736 on;
insert t4721736(id,name,comm) select 10000000, 'Smith', 334.23;
set identity_insert t4721736 off;
-- reset the identity
set #resetto = #resetto - 1 -- it needs to be 1 prior
DBCC CHECKIDENT(t4721736, RESEED, #resetto)
COMMIT
Assuming you fully understand (I believe you do) that it will fail as soon as the range runs up to the records with the nominated IDs. SQL Server won't perform any auto-skip over IDs that already have records attached.
that will not be a problem, coz when i
insert using identity_insert on, value
of id will be greater than 10 million.
so there will not be any problem of
clashing
To see how this fails, shortcut the process by changing the "10000000" into "10" in the code above. Then, follow up with these:
-- inspect contents, shows records 1,2,10
select * from t4721736
-- next, insert 7 more records, bringing the id up to 9
insert t4721736 select 'U3', 0
insert t4721736 select 'U4', 0
insert t4721736 select 'U5', 0
insert t4721736 select 'U6', 0
insert t4721736 select 'U7', 0
insert t4721736 select 'U8', 0
insert t4721736 select 'U9', 0
Finally, try the next insert below
insert t4721736 select 'U10', 0
You can reset the seed value using DBCC CHECKIDENT:
DBCC CHECKIDENT ("MyTable", RESEED, 3);
GO
However, you have inserted a record Id of 10, so yes, the next one will indeed be 11.
It is documented on the command:
If the current identity value for a table is less than the maximum identity value stored in the identity column, it is reset using the maximum value in the identity column.
You can't have it both ways. Either have the lowest ID be the value of the base seed, or not.
If these rows you're inserting are special/magic rows (so they need specific IDs), have you considered making these rows have negative ID values? That way there's no conflict, and the IDENTITY value will not be reset by your adding them.
If it's some other reason why you need to insert these rows with vastly different ID values, perhaps you could expand your question to provide some info on that - we may be able to offer better solutions.
Another way to get around the "planted bug" dilemma is to create your own identity generator procedure and tracking table. The table includes a tablename and value that the next ID should be. This way you can reset it any value at any time. The procedure would include logic to check to see if the next generated key exists and if it does exist it will increment the key till it finds an ID that does not exist in the table and pass that back out to you. This would have to be implemented on all inserts to work correctly. Which is possible with a trigger. The downside is more processing overhead than using a negative number like Damien_The_Unbeliever suggests.