How to make an auto-incrementing id column use missing numbers in SQL Server? - sql

Say I have a table with 100 rows and an auto-incrementing id column, and I delete the row with id = 15. How can I add a new row with id = 15 instead of id = 101?

No, don't do it.
Generated primary keys are used to produce unique values, that are of internal use. They are not supposed to "sexy" or nice looking. That is NOT their purpose; the PK purpose is uniqueness. If you are concerned about the specific values, then it means you are exposing the PK to the external world... something that raises a lot of red flags.
If you need a value to expose, don't use the PK fot this, but create a secondary column for it. Its solely purpose in the world is to be exposed. This value can have a nice formatting with dashes (like the SSN), prefixes, suffixes, etc.

If you have a table with an identity key field you could use this:
SET IDENTITY_INSERT YourTableName ON
INSERT INTO YourTableName (ID, Other) VALUES (15, 'Whatever')
SET IDENTITY_INSERT YourTableName OFF

Related

Adding Row in existing table (SQL Server 2005)

I want to add another row in my existing table and I'm a bit hesitant if I'm doing the right thing because it might skew the database. I have my script below and would like to hear your thoughts about it.
I want to add another row for 'Jane' in the table, which will be 'SKATING" in the ACT column.
Table: [Emp_table].[ACT].[LIST_EMP]
My script is:
INSERT INTO [Emp_table].[ACT].[LIST_EMP]
([ENTITY],[TYPE],[EMP_COD],[DATE],[LINE_NO],[ACT],[NAME])
VALUES
('REG','EMP','45233','2016-06-20 00:00:00:00','2','SKATING','JANE')
Will this do the trick?
Your statement looks ok. If the database has a problem with it (for example, due to a foreign key constraint violation), it will reject the statement.
If any of the fields in your table are numeric (and not varchar or char), just remove the quotes around the corresponding field. For example, if emp_cod and line_no are int, insert the following values instead:
('REG','EMP',45233,'2016-06-20 00:00:00:00',2,'SKATING','JANE')
Inserting records into a database has always been the most common reason why I've lost a lot of my hairs on my head!
SQL is great when it comes to SELECT or even UPDATEs but when it comes to INSERTs it's like someone from another planet came into the SQL standards commitee and managed to get their way of doing it implemented into the final SQL standard!
If your table does not have an automatic primary key that automatically gets generated on every insert, then you have to code it yourself to manage avoiding duplicates.
Start by writing a normal SELECT to see if the record(s) you're going to add don't already exist. But as Robert implied, your table may not have a primary key because it looks like a LOG table to me. So insert away!
If it does require to have a unique record everytime, then I strongly suggest you create a primary key for the table, either an auto generated one or a combination of your existing columns.
Assuming the first five combined columns make a unique key, this select will determine if your data you're inserting does not already exist...
SELECT COUNT(*) AS FoundRec FROM [Emp_table].[ACT].[LIST_EMP]
WHERE [ENTITY] = wsEntity AND [TYPE] = wsType AND [EMP_COD] = wsEmpCod AND [DATE] = wsDate AND [LINE_NO] = wsLineno
The wsXXX declarations, you will have to replace them with direct values or have them DECLAREd earlier in your script.
If you ran this alone and recieved a value of 1 or more, then the data exists already in your table, at least those 5 first columns. A true duplicate test will require you to test EVERY column in your table, but it should give you an idea.
In the INSERT, to do it all as one statement, you can do this ...
INSERT INTO [Emp_table].[ACT].[LIST_EMP]
([ENTITY],[TYPE],[EMP_COD],[DATE],[LINE_NO],[ACT],[NAME])
VALUES
('REG','EMP','45233','2016-06-20 00:00:00:00','2','SKATING','JANE')
WHERE (SELECT COUNT(*) AS FoundRec FROM [Emp_table].[ACT].[LIST_EMP]
WHERE [ENTITY] = wsEntity AND [TYPE] = wsType AND
[EMP_COD] = wsEmpCod AND [DATE] = wsDate AND
[LINE_NO] = wsLineno) = 0
Just replace the wsXXX variables with the values you want to insert.
I hope that made sense.

Is it possible to assign to a UNIQUEIDENTIFIER field automatically in each insertion?

I have a table in which I have an INT IDENTITY(1,1) PRIMARY KEY field, and right next to it an UNIQUEIDENTIFIER field which I would like to be automatically assigned upon each insertion on the table. I tried setting DEFAULT NEWID(), but it only works if I do INSERT INTO TableName VALUES (DEFAULT, a, b, c, d, ...). What I would like would be to be able to do INSERT INTO TableName VALUES (a, b, c, d, ...) and the UNIQUEIDENTIFIER field be automatically assigned just like the primary key field. Is that possible? Please not that, although it is a valid thing to do, I don't want to have this field as (part of a) primary key for the table.
Use column list then and omit the PK, GUID columns
INSERT INTO TableName (col3, col4, col5, ...)
VALUES (a, b, c, d, ...) a
Using DEFAULT works around lack of column list which is best practice anyway. For example, what if you reorder or add columns? And using a trigger isn't optimal or scalable
Edit: Using a trigger is a workaround to avoid best practice... and won't scale too well
gbn is right. I'll just add a couple of other points you need to consider.
If you have a unique ID on your table, then why would you want or need a UNIQUEIDENTIFIER? You should probably choose one or the other as your PK, but not both. Also, when choosing a default for the database, choose NEWSEQUENTIALID() instead of NEWID().
It should be the Default value in the table schema. So you do not need to bother about this column after setting the default value.
Open the table design window and select the column which is supposed to occupy the GUID information. For more information, Please see below the screen shot.
So, by setting the (newID()) as a default value will let you insert the record without incorporating this column name in your insert statement.
Please let me know in case of any confusion

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?

SQL: dealing with unique values in the table when UNIQUE key constraint isn't applicable

What you do when you need to maintain a table with unique values when you can't use UNIQUE constraint?
For example, I use MySQL and want to map my urls to ids. So I create a table:
CREATE TABLE url (id INTEGER PRIMARY KEY AUTO_INCREMENT, url VARCHAR(2048));
The problem is that mysql doesn't allow unique field bigger than 1000 bytes.
How in general do insert only if not exist in sql atomically?
You could create an extra field which would be the hash of a url e.g. md5, and make that hash field unique. You can certainly be sure that the URL is unique then, and with almost 100% certainty you can insert a new URL if it isn't already there.
It is tempting to create a table lock, however creating a table lock will implicitly commit the transaction you are working on: http://www.databasesandlife.com/mysql-lock-tables-does-an-implicit-commit/
You could create a single-row table e.g. name mutex, type=InnoDB, insert a row into it, and do a select for update on that row to create a lock which is compatible with transactions. It's nasty but that's the way I do table locks in MySQL in my applications :(
You could use a not exist condition:
insert YourTable
(url)
values ('blah blah blah')
where not exists
(
select *
from YourTable
where url = 'blah blah blah'
)
In my opinion the best way to handle it is to write a trigger. The trigger is going to check each value in the table to see whether they are equal and if yes, to raise an error. However, I don't think an URL will go beyond 1000 characters but if it does in your case, you should write a trigger to handle the uniqueness.

SQL IDENTITY COLUMN

I have an sql table which is basically a statement.
Now lets say the records I have in my table have a date and an identity column which is autonumbered and defines the order which the transactions are displayed in the front end to the client.
The issue is during an insert some of the data have gone missing and some transactions between two dates are missing.
I need to insert the data into the table, but I need to insert them between the dates and not at the end of the table. If I do a a normal insert, the data will appear at the end of the table and not at the date I specify, because the identity column is autonumbered, and cannot be updated.
Using SET IDENTITY_INSERT (table) ON, you force SQL Server to let you insert any arbitrary value into an IDENTITY column - but there's no way to update an IDENTITY column.
What's the big problem with a few gaps anyway?? Yes, it might be a bit of a "cosmetic" problem - but how much hassle and effort do you really want to spend on cosmetic problems?? The order of the entries is still a given - even with gaps.
So again: what's the big deal?? IDENTITY columns are guaranteed to be ever increasing - that's all they guarantee. And for 99% of the cases, that's more than good enough....
Why not just display the records in the user interface sorted by the date, rather than by the primary key?
OK, if you really want to do this (personally, I think changing the sort date in the UI is going to be easier than updating the primary key values in the database, but anyway...). This should work, assuming you're not using the primary key values in any foreign key constraints (if you are, then you'll need to make sure those constraints have ON UPDATE CASCADE set)
SET IDENTITY_INSERT tablename ON
UPDATE tablename SET
primary_key = primay_key + 1
WHERE
primary_key >= <the primary key where you want to insert the new date>
INSERT INTO tablename
(primary_key, date, ...)
VALUES
(<the primary key to insert>, <the date to insert>, ...)
SET IDENTITY_INSERT tablename OFF
However, I strongly, strongly suggest you backup your database before attempting this.
Just out of curiosity, is it one ID per date? Your answers imply this a little, so if so, replace the Identity column with a computed column that is defined as the date difference in days from an arbitrary starting point?
DECLARE #EXAMPLE TABLE
(
[Date] DATE,
ID AS DATEDIFF(Day, '1 Jan 2010', [Date])
)
INSERT INTO #EXAMPLE([Date])
VALUES (GETDATE()), (GETDATE()+1), (GETDATE()+2)
SELECT * FROM #EXAMPLE