Auto-increment id when field is empty - database

How to avoid auto-increment in database table when field is empty (whenever i leave project_id, project_name etc, it still automatically increment the id). What should i do to avoid this ?

I dont think (as far as i know) auto increment can be stopped. Any insert to the table will cause the counter to increment ( hence the name auto-increment).
Say suppose you inserted a row and the auto increment value was 10. Now delete that row and insert a new row. The value 10 wont be reused.
My advise would be to be more careful while inserting values (add as many checks as required) into the database or remove the auto increment and provide a key manually - query to get max of that column, increment it by 1 and used this new value to insert to the database(not a particularly good idea especially if the database size is huge).

Related

How can the date a row was added be in a different order to the identity field on the table?

I have a 'change history' table in my SQL Server DB called tblReportDataQueue that records changes to rows in other source tables.
There are triggers on the source tables in the DB which fire after INSERT, UPDATE or DELETE. The triggers all call a stored procedure that just inserts data into the change history table that has an identity column:
INSERT INTO tblReportDataQueue
(
[SourceObjectTypeID],
[ActionID],
[ObjectXML],
[DateAdded],
[RowsInXML]
)
VALUES
(
#SourceObjectTypeID,
#ActionID,
#ObjectXML,
GetDate(),
#RowsInXML
)
When a row in a source table is updated multiple times in quick succession the triggers fire in the correct order and put the changed data in the change history table in the order that it was changed. The problem is that I had assumed that the DateAdded field would always be in the same order as the identity field but somehow it is not.
So my table is in the order that things actually happened when sorted by the identity field but not when sorted by the 'DateAdded' field.
How can this happen?
screenshot of example problem
In example image 'DateAdded' of last row shown is earlier than first row shown.
You are using a surrogate key. One very important characteristic of a surrogate key is that it cannot be used to determine anything about the tuple it represents, not even the order of creation. All systems which have auto generated values like this, including Oracles sequences, make no guarantee as to order, only that the next value generated will be unique from previous generated values. That is all that is required, really.
We all do it, of course. We look at a row with ID of 2 and assume it was inserted after the row with ID of 1 and before the row with ID of 3. That is a bad habit we should all work to break because the assumption could well be wrong.
You have the DateAdded field to provide the information you want. Order by that field and you will get the rows in order of insertion (if that field is not updateable, that is). The auto generated values will tend to follow that ordering, but absolutely do not rely on that!
try use Sequence...
"Using the identity attribute for a column, you can easily generate auto-
incrementing numbers (which as often used as a primary key). With Sequence, it
will be a different object which you can attach to a table column while
inserting. Unlike identity, the next number for the column value will be
retrieved from memory rather than from the disk – this makes Sequence
significantly faster than Identity.
Unlike identity column values, which are generated when rows are inserted, an
application can obtain the next sequence number before inserting the row by
calling the NEXT VALUE FOR function. The sequence number is allocated when NEXT
VALUE FOR is called even if the number is never inserted into a table. The NEXT
VALUE FOR function can be used as the default value for a column in a table
definition. Use sp_sequence_get_range to get a range of multiple sequence
numbers at once."

Avoiding gaps in an identity column

I have a table in MS SQL SERVER 2008 and I have set its primary key to increment automatically but if I delete any row from this table and insert some new rows in the table it starts from the next identity value which created gap in the identity value. My program requires all the identities or keys to be in sequence.
Like:
Assignment Table has total 16 rows with sequence identities(1-16) but if I delete a value at 16th position
Delete From Assignment Where assignment_id=16;
and after this operation when I insert a new row
Insert into Assignment(assignment_title)Values('myassignment');
Rather than assigning 16 as a primary key to this new value it assigns 17.
How can I solve this Problem ?
Renaming or re-numbering primary key values is not a good database management practice. I suggest you keep the primary key as is, and create a separate column index with the values you require to be re-numbered. Then simply create a trigger to run a routine that will re-number every row in the order you expect, obviously by seeking the "gaps" and entering them with values incremented from their previous value.
This is SQL Servers standard behaviour. If you deleted a row with ID=8 in your example, you would still have a gap.
All you could do, is write a function getSmallestDreeID in SQL Server, that you called for every insert and that would get you the smallest not assigned ID. But you would have to take great care of transactions and ACID.
The behavior you desire isn't possible without some post processing logic to renumber the rows.
Consider thus scenario:
Session 1 begins a transaction, inserts a row (id=16), but doesn't commit yet.
Session 2 begins a transaction, inserts a row (id=17) and commits.
Session1 rolls back.
Whether 16 will or will not exist in the table is decided after 17 is committed.
And you can't renumber these in a trigger, you'll get deadlocked.
What you probably need to do is to query the data adding a row number that is a sequential integer.
Gaps in identity values isn't a problem
well, i have recently faced the same problem: i need the ID values in an external C# application in order to retrieve files named exactly as the ID.
==> here is what i did to avoid the identity property, i entered id values manually because it was a small table, but if it is not in your case, use a SEQUENCE SQL Server 2014.
Use the statement UPDATE instead of delete to keep the id values in order.

How can I get current autoincrement value

How can I get last autoincrement value of specific table right after I open database? It's not last_insert_rowid() because there is no insertion transaction. In other words I want to know in advance which number autoincrement will choose when inserting new row for particular table.
It depends on how the autoincremented column has been defined.
If the column definition is INTEGER PRIMARY KEY AUTOINCREMENT, then SQLite will keep the largest ID in an internal table called sqlite_sequence.
If the column definition does NOT contain the keyword AUTOINCREMENT, SQLite will use its ‘regular’ routine to determine the new ID. From the documentation:
The usual algorithm is to give the newly created row a ROWID that is
one larger than the largest ROWID in the table prior to the insert. If
the table is initially empty, then a ROWID of 1 is used. If the
largest ROWID is equal to the largest possible integer
(9223372036854775807) then the database engine starts picking positive
candidate ROWIDs at random until it finds one that is not previously
used. If no unused ROWID can be found after a reasonable number of
attempts, the insert operation fails with an SQLITE_FULL error. If no
negative ROWID values are inserted explicitly, then automatically
generated ROWID values will always be greater than zero.
I remember reading that, for columns without AUTOINCREMENT, the only surefire way to determine the next ID is to VACUUM the database first; that will reset all ID counters to the largest existing ID for that table + 1. But I can’t find that quote anymore, so this may no longer be true.
That said, I agree with slash_rick_dot that fetching auto-incremented IDs beforehand is a bad idea, especially if there’s even a remote chance that another process might write to the database at the same time.
Different databases implement auto-increment differently. But as far as I know, none of them will answer the question you are asking.
The auto increment feature is intended to create a unique ID for a newly added table row. If a row hasn't been inserted yet, then the feature hasn't produced the id.
And it makes sense... If you did get the next auto increment number, what would you do with it? Likely the intent is to assign it as the primary key of the not-yet-inserted new row. But between the time you got the id, and the time you used it to insert the row, the database could have used that id to insert a row for another process.
Your choices are this: manage the creation of ids yourself, or wait until rows are inserted before using their auto-created identifiers.

How to insert empty record in a table

----------
ID NAME
3 A
4 B
5 C
----------
when i delete all record, it continues after number five's record, but i want it must be insert first index of this table. can anyone help me?
I assume you've got your ID column as an IDENTITY column, and you want to reset it to start again at 1, after having removed all rows from the table.
First, I'd say that having such a need (that the ID value start at 1) tends to mean there's something wrong with what you're doing - IDENTITY columns can always have gaps in the numbering, and should be treated as opaque blobs. The fact that they appear to be integers, and tend to be easy to remember, are just implementation details.
Second, if you want to do such a reset, you'd use DBCC CHECKIDENT
Edit
If you really do depend on these ID values (say, because they're also used in an application), it's a good indicator that the column shouldn't have the IDENTITY property in the first place. Unfortunately, you can't directly remove this property - you'd have to create a copy of the table without this property, copy all rows across, delete the original table, and rename the copy. Management Studio will pretend you can just remove the property, but will do what I've just described behind the scenes.
A simple way would be to
TRUNCATE TABLE mytable;
instead of
DELETE FROM mytable
From TRUNCATE TABLE (Transact-SQL)
If the table contains an identity column, the counter for that column is reset to the seed value defined for the column. If no seed was defined, the default value 1 is used. To retain the identity counter, use DELETE instead.
Looks like your ID column is an IDENTITY column - these will always add the next value (regardless of deletes).
The requirement to have a specific ID does sound like your application design relies on it, which is not good practice. ID fields do have gaps (which is normal) - your application shouldn't rely on them.
Regardless, here are a couple of ways of doing this:
For a one off, use SET IDENTITY INSERT ON:
SET IDENTITY INSERT dbo.myTable ON
INSERT INTO myTable
(ID, NAME)
VALUES
(1, 'H')
SET IDENTITY INSERT dbo.myTable OFF
To reset the seeding, you need to use a DBCC CHECKIDENT command, using RESEED:
DBCC CHECKIDENT('myTable', RESEED, 0)
I think you want to restart the value of the autogenerated id column with 1 again?
if it is an IDENTITY column, you can reset the seed value with teh following command
DBCC CHECKIDENT('YourTableNameHere', RESEED, 0)
Databases ID feature are intended to go sure different records will NEVER have the same ID. This is not only valid for records existing at the same time, but also for new records being inserted after another one was deleted. This is extremely useful to avoid conflicts. Although it seems to sometimes break some people's sense of taste don't work around it.
If you need to assign self chosen numbers to the records add another column. Auto-indexed columns should be used all the time. The other users told you how to fiddle with the index but use this feature very careful.

Does SQL Server guarantee sequential inserting of an identity column?

In other words, is the following "cursoring" approach guaranteed to work:
retrieve rows from DB
save the largest ID from the returned records for later, e.g. in LastMax
later, "SELECT * FROM MyTable WHERE Id > {0}", LastMax
In order for that to work, I have to be sure that every row I didn't get in step 1 has an Id greater than LastMax. Is this guaranteed, or can I run into weird race conditions?
Guaranteed as in absolutely under no circumstances whatsoever could you possibly get a value that might be less than or equal to the current maximum value? No, there is no such guarantee. That said, the circumstances under which that scenario could happen are limited:
Someone disables identity insert and inserts a value.
Someone reseeds the identity column.
Someone changes the sign of the increment value (i.e. instead of +1 it is changed to -1)
Assuming none of these circumstances, you are safe from race conditions creating a situation where the next value is lower than an existing value. That said, there is no guarantee that the rows will be committed in the order that of their identity values. For example:
Open a transaction, insert into your table with an identity column. Let's say it gets the value 42.
Insert and commit into the same table another value. Let's say it gets value 43.
Until the first transaction is committed, 43 exists but 42 does not. The identity column is simply reserving a value, it is not dictating the order of commits.
I think this can go wrong depending on the duration of transactions
Consider the following sequence of events:
Transaction A starts
Transaction A performs insert - This creates a new entry in the identity column
Transaction B starts
Transaction B performs insert - This creates a new entry in the identity column
Transaction B commits
Your code performs its select and sees the identity value from the 2nd transaction
Transaction A commits -
The row inserted by Transaction A will never be found by your code. It was not already committed when step 6 was performed. And when the next query is performed it will not be found, because it has a lower value in the identity column than the query is looking for.
It could work if you perform the query with a read-uncommitted isolation mode
Identities will will always follow the increment that defines the identity:
IDENTITY [(seed ,increment)] http://msdn.microsoft.com/en-us/library/aa933196(SQL.80).aspx
which can be positive or negative (you can have it increment forward or backwards). If you set your identity to increment forward, your identity values will always be larger than the previous, but you may miss some, if you rollback an INSERT.
Yes, if you set your identity increment to a positive value your loop logic will work.
The only time records might get inserted that you wouldn't get would be if someone turns the identity insert on and manually inserts a record to a skipped id (or in some cases to a negative number). This is a fairly rare occurance and generally would only be done by a system admin. Might be done to reinsert an accidentally deleted record for instance.
The only thing that SQL Server guarantees is that your IDENTITY column will always be incremented.
Things to consider though:
If a fail INSERT occurs, the IDENTITY column will get incremented anyhow;
If a rollback occurs, the IDENTITY column will not return to its previous value;
Which explains why SQL Server doesn't guarantee sequential INDENTITY.
There is a way to reset an IDENTITY column like so using the DBCC command. But before doing so, please consider the following:
Ensure your IDENTITY column is not referenced by any other table, as your foreign keys could be not updated with it, so big troubles ahead;
You might use the SET IDENTITY_INSERT ON/OFF instruction so that you may manually specify the IDENTITY while INSERTing a row (never forget to turn it on afterward).
An IDENTITY column is one of the most important element never to be changed in DBRMs.
Here is a link that should help you: Understanding IDENTITY columns
EDIT: What you seem to do shall work as the IDENTITY column from LastMax will always increment for each INSERTed row. So:
Selecting rows from data table;
Saving LastMax state;
Selecting rows where Id > LastMax.
3) will only select rows where the IDENTITY column will be greater than LastMax, so inserted since LastMax has been saved.

Resources