Checking the identity of a new table for database unit tests - sql-server

I have a suite of database unit tests that were created. In order to replicate all of the tests on any machine I deploy out to there are scripts to drop the database and recreate it. The test will work for all of the unit tests except for the first test.
The reason the first test fails is that I am executing the "dbcc checkident" command before each test and resetting all of the identities in order to ensure that all of the identities are the same. On a new table that has never been inserted into and then has "dbcc checkident" ran against it the identity starts at 0 when inserted into instead of 1.
If I use some of the other built in commands to check the identity in a fresh table, they return 0 as the identity. The benefit for checking through "dbcc checkident" is that the identity comes back as 'NULL' if a row has never been inserted into it. Only "dbcc checkident" tells us through a print message and cannot easily be tested.
How can I verify that that I need to reset the identity or not through database commands without inserting a row, deleting it, then resetting just to avoid the identity from getting off on the first record?
Example of inserting into a table
Identity after inserting a row on a fresh table without running "dbcc checkident" and setting identity to 0 = 1
Identity after inserting a row on a fresh table and running "dbcc checkident" and setting identity to 0 = 0
Identity after inserting a row on an existing table thats been inserted into and running "dbcc checkident" and setting identity to 0 = 1

To get around the identity insert problem with "dbcc checkident" on a new table, here's what I did.
Using the sys tables I was able to manually check the last identity value through sql. If the last identity was reset, it will change the last value to 0. On a new table that has never been inserted into the last identity will be null.
Here is the code snippet we used. This will allow you to check the last identity without doing an insert, delete, reset identity.
-- {0} is your table name
-- {1} is your identity value of the reset
IF EXISTS (SELECT null FROM sys.identity_columns WHERE OBJECT_NAME(OBJECT_ID) = '{0}' AND last_value IS NOT NULL)
DBCC CHECKIDENT ({0}, RESEED, {1});

Related

Trying to reset Identity value for SQL Azure DB Table column

I am using SQL Azure. I have a deployment DB and a test DB
I would like to add some new lookup records to the Test DB, to test new code.
Initially My Deployment DB's Identity was set to 200000+ for the PKs, and my Test DB to 100000+, to prevent PK collisions when syncing using such tools as Redgates' SQL data compare.
Unfortunately I made a mistake, and copied the Deployment DB as the new Test DB, since we required a more up to date dataset. As a result my Test DB now starts at 200000+. So I now have the risk of conflicts when syncing with the Deployment DB.
I would normallly just use:
DBCC CHECKIDENT('TableName', RESEED, 105000)
However SQL Azure does not support this.
I have come across a workaround:
set identity_insert TableName on -- this basically turns off IDENTITY
INSERT INTO TableName(id, name) VALUES (104999,'Test Reset Identity Start 104999') -- so we can jam any value for column ID
set identity_insert TableName off -- then turn it back on
INSERT INTO TableName(name) VALUES ('Test Reset Identity End') -- ID starts at 105000, in theory, from this point
SELECT * FROM TableName
However the new Identify value always seems to take the highest PK in the table as the last seed, rather than the PK value from the last inserted record.
I would rather not rebuild the table.
Is there another approach to resetting the identity value for my situation, ie to a lesser number ie 104999 rather the current 204999?
Thanks in advance.
EDIT 1
It may be I can only check the identity value to a value greater than the current value ie to say 206000 ?
EDIT 2
Perhaps there is an argument that Identity value should never be reseed to less than the max PK value, even if there is 100,000 spare numbers, as one day you will get a collision.

Some tables id column do not auto increment despite being identity

I am troubleshooting a db (not my forte) that has some tables that are auto incrementing on the id column and some tables are not?
Now all the tables are set as identity and marked to disallow null. I am using SSMS what else can I check or do to get these tables back to auto incrementing?
TIA
Interestingly to me...probably old news to you guys. The issue had to do with existing data. So for example a table that had 100 rows in did NOT have the identity column setup. So I would go in and make it an identity with a seed of 1 incrementing 1. Well the seed was somehow having trouble because there was already 100 rows in there. So for all my tables I had to do a row count and seed the identity from the next row. Now it is working as expected.
Having an IDENTITY column is pretty straightforward for a table, and if you are not seeing the auto incrementing behavior of a column on inserts, then I'd first verify that your column is indeed an IDENTITY column:
use <Your Database Name>;
go
select
name,
is_identity
from sys.columns
where object_id = object_id('<Your Table Name>')
order by column_id;
Substitute <Your Database Nam> and <Your Table Name> for their appropriate values.
The other possibility is that data that "appears" to be non-incrementing could have been pushed out to that with a session that set identity insert and pushed out explicit values.
ALTER TABLE YourTable MODIFY COLUMN YourTable_id int(4) auto_increment

Load empty database table

I am using SQL Server Express and VS2008.
I have a database with a table A, which has a column ID as IDENTITY. The ID is auto-incremented. Even if the row is deleted, the ID still increases.
After several data manipulation, the current ID has reached 15, for example.
When I run the application
if there's at least 1 row: if I add a new row, the new ID is 16. Everything is fine.
If the table is empty (no row): if I add a new row, the new ID is 0, which is an error (I think).
And further data manipulation (e.g. delete or update) will result in an unhandled exception.
Has anyone encountered this?
PS. In my table definition, the ID has been selected as follow:
Identity Increment = 1; Identity Seed =1;
The DB load code is:
dataSet = gcnew DataSet();
dataAdapter->Fill(dataSet,"A");
dataTable=dataSet->Tables["A"];
dbConnection->Open();
The Update button method
dataAdapter->Update(dataSet,"tblInFlow");
dataSet->AcceptChanges();
dataTable=dataSet->Tables["tblInFlow"];
dataGrid->DataSource=dataTable;
If I press Update:
if there's at least a row: the datagrid view updates and shows the table correctly.
if there's nothing in the table (no data row), the Add method will add a new row, but from ID 0.
If I close the program and restart it again: the ID would be 16, which is correct.
This is the add method
row=dataTable->NewRow();
row["column1"]="something";
dataTable->Rows->Add(row);
dataAdapter->Update(dataSet,"A");
dataSet->AcceptChanges();
dataTable=dataSet->Tables["A"];
If you are deleting the date using
Delete from myTable
It will not reset the identity column but on the other hand if your truncating the table then it will reset any identity columns to the default seed value ( in your case starting from 1)
If you are truncating the table and then reseeding it ,the first identity reseed value will be 0 if you write
DBCC CHECKIDENT(MyTable, RESEED, 0)
Even though your identity column is specified as Identity=1 and seed =1 ,the very first row inserted will start from the Id=0
If you want to start from 1 then you need to reseed the column as
DBCC CHECKIDENT(MyTable, RESEED, 1)

Insert data in to sql server data table

I have one table called customer_master that includes a column called cust_id with autoincrement set to 1.
When we try to insert records its working fine and inserted records like cust_id 1, 2, 3 and 4 are inserted, but when an error is generated in the insert command we do a transaction rollback, this means that cust_id 5 is not inserted, but when we are insert another record, cust_id generates 6. It skips cust_id 5.
I want to set it up so that if any error is generated in the insert command the identity is not incremented.
We are using c# and sql server 2005.
The reason SQL Server does this is for efficiency. If you need a sequence number without gaps you shouldn't be using identity you would need to implement your own scheme where concurrent transactions are blocked waiting for the next value just in case the initial transaction rolls back.
The second query here could be used for that purpose. But do you really need this? If it is purely for aesthetic purposes my advice is not to worry about it!
You can use DBCC CHECKIDENT to reseed the identity column after an insert failure.
DBCC CHECKIDENT ( table_name, NORESEED ) returns the current identity value and the current maximum value of the identity column.
DBCC CHECKIDENT ( table_name, RESEED, new_reseed_value ) sets the current identity value to the new_reseed_value.

Insert into replicated table fails - identity range check

I'm trying to insert a few thousand rows into a table in a database that is replicated across two servers. From either the publisher or the subscriber, I get the same error:
Msg 548, Level 16, State 2, Line 1
The insert failed. It conflicted with an identity range check constraint in database 'XXX', replicated table 'dbo.NODE_ATTRIB_RSLT', column 'ID'. If the identity column is automatically managed by replication, update the range as follows: for the Publisher, execute sp_adjustpublisheridentityrange; for the Subscriber, run the Distribution Agent or the Merge Agent.
The statement has been terminated.
Checking the constraint on the table, it seems to me like I should be able to insert at least 1000 rows at a time before running into issues. However, I get the same error when trying to insert just a few tens of rows!
Here's how I'm trying to insert data:
insert into NODE_ATTRIB_RSLT
([NODE_ID]
,[ATTRIB_ID]
,[STATE_ID]
,[PLAN_REVISION_ID]
,[TIMESTAMP]
,[VALUE]
,[VALUE_TEXT]
,[LAST_MODIFIED])
SELECT [NODE_ID]
,[ATTRIB_ID]
,[STATE_ID]
,[PLAN_REVISION_ID]
,[TIMESTAMP]
,[VALUE]
,[VALUE_TEXT]
,[LAST_MODIFIED] FROM [NODE_ATTRIB_RSLT_TEMP]
The PK column is an autogenerated identity called ID. To try to insert fewer rows at a time I've added a WHERE clause at the end of the select like so:
WHERE ID >= 1000 and ID <1100
but to no avail.
Running sp_adjustpublisheridentityrange on the Publisher executes successfully but has no effect.
How can I fix this problem with inserts?
How can I modify the ranges of the indentity range contraints to a more reasonable level while leaving the replication running?
I think I worked out what the problem was.
Looking at the properties for the replicated table, it had the standard default identity range of 10000 for the Publisher and 1000 for the Subcriber.
However, checking the identity constraint on the actual table (using SP_HELPCONSTRAINT 'node_attrib_rslt') revealed that there was only a pool of 1000 IDs on both servers. This made the bulk insert fail even when I restricted the number of rows to insert - I'm guessing SQL Server doesn't even get that far when it checks the constraint when running an INSERT INTO.
To fix it I had to do several things:
Change the identity range of the table. I set it up to 20K for both Publisher and Subcriber.
On the Publisher, expand Replication --> Local Publications
Right-click the particular subscription and choose Properties.
Select the Articles page.
Highlight the appropriate Table.
Click on the Article Properties 'button', and choose 'Set Properties of Highlighted Table Article'.
In the Article Properties window, look for Identity Range Management options.
Change the appropriate values.
Press OK and OK on the dialog windows.
Run the sp_adjustpublisheridentityrange stored proc on the Publisher.
New query window on the server
Choose the correct database
Execute sp_adjustpublisheridentityrange #table_name = 'node_attrib_rslt'
From the subcriber, force-synchronise the servers.
On the Subscriber, expand Replication --> Local Subcriptions
Right-click the particular subscription and choose View Subscription Status.
In the dialog that appears, press the monitor button.
In the Replication Monitor window that appears, expand the particular Publisher in the left hand pane.
Click on the Subcription to edit.
In the right hand pane, right-click on the subcription status and choose Start Synchronising.
The status should update to 'Synchronising' while it does its thing.
After it's finished, click on the 'Warnings and Agents' tab. I had a 'Snapshot Agent' listed in the lower pane. Right click on that Agent and start it. After it had been running for a while, the change of properties on the server should have migrated to the client.
Maybe: insert some test rows into the table.
Edit: I've had to do this task again recently, and the constraint on the table would not update until I inserted a bunch of dummy data into the table so as to exhaust the default constraint. Then I resyncronised the servers, and the constraint was updated to the new value.
After that, checking the identity constraint revealed that I finally had a 20K ID range to insert with on both the Publisher and the Subcriber.
I had this exact same issue, and the above solution didn't do anything for me.
Instead what ended up solving the issue was by setting the new, larger identity ranges on the tables in the publication, and then dropping the identity constraints on the table
And then finally running this command that sets the current identity.
DBCC CHECKIDENT ('TableName', RESEED, 1000000000);
Instead of setting the value to 1000000000, the constraint is created again, and set to the correct identity range value currently specified on the table in the publication.
It looks like the CHECKIDENT command forces the constraint to be updated somehow.
The above solution worked for me, but was actually my attempt at just dropping the constraints and setting the publisher and subscriber to use different identity ranges so they would be able to insert rows in the tables. Fortunately the CHECKIDENT seemed to refresh the constraint, something i originally expected the sp_adjustpublisheridentityrange stored procedure to do - except it did nothing.
I ran the above command on both the publisher and the subscriber.

Resources