Autoincrement in Oracle(Adjust the ID sequence after deleting) - sql

CREATE TABLE test
(id NUMBER PRIMARY KEY,
name VARCHAR2(30));
CREATE SEQUENCE test1_sequence
START WITH 1
INCREMENT BY 1;
INSERT INTO test (id, name) VALUES (test1_sequence.nextval,'Jon');
INSERT INTO test (id, name) VALUES (test1_sequence.nextval,'Hello');
INSERT INTO test (id, name) VALUES (test1_sequence.nextval,'Matt');
INSERT INTO test (id, name) VALUES (test1_sequence.nextval,'Bork');
And suppose if I deleted one record from this table by-
delete from test where id='2';
then If I do select query-
select * from test;
then I get
ID Name
1 Jon
3 Matt
4 Bork
So If I need to maintain the order of id, like as soon as I delete any data it adjusts the id automatically. So I should be getting the table as
ID Name
1 Jon
2 Matt
3 Bork
Any suggestions how can I do this..

If I remember correctly from articles on Ask Tom website, sequence DOES NOT guarantee that it will produce gap free numbers. So the way you are filling up your table and generating ID's will never be 100% gap free (even without deleting rows).
Here's one of the articles on that subject: http://asktom.oracle.com/pls/apex/f?p=100:11:0::::P11_QUESTION_ID:4343369880986
Also keep in mind that you are updating (what seems a) primary key column.
My suggestion is not to do it. If you need a ordered list of rows, use ROW_NUMBER and leave PK to be a surrogate key without attaching any "application meaning" to it.

Related

Database cache in SQL Or correcting autoincrement [duplicate]

This question already has answers here:
How to get rid of gaps in rowid numbering after deleting rows?
(4 answers)
Closed 5 months ago.
I've created 2 rows in an table in SQL (sqlite3 on cmd) and then deleted 1 of them.
CREATE TABLE sample1( name TEXT, id INTEGER PRIMARY KEY AUTOINCREMENT);
INSERT INTO sample1 VALUES ('ROY',1);
INSERT INTO sample1(name) VALUES ('RAJ');
DELETE FROM sample1 WHERE id = 2;
Later when I inserted another row, its id was given 3 by the system instead of 2.
INSERT INTO sample1 VALUES ('AMIE',NULL);
SELECT * FROM sample1;
picture of table
How do I correct it so the next values are given right id's automatically? Or how do I clear the sql database cache to solve it?
The simplest fix to resolve the problem you describe, is to omit AUTOINCREMENT.
The result of your test would then be as you wish.
However, the rowid (which the id column is an alias of, if INTEGER PRIMARY KEY is specified, with or without AUTOINCREMENT), will still be generated and probably be 1 higher than the highest existing id (alias of rowid).
There is a subtle difference between using and not using AUTOINCREMENT.
without AUTOINCREMENT then the generated value of the rowid and therefore it's alias will be the highest existing rowid for the table plus 1 (not absolutely guaranteed though).
with AUTOINCREMENT the generated value will be 1 plus the higher of:-
the highest existing rowid, or
the highest used rowid
the highest, in some circumstances, may have only existed briefly
In your example as 2 had been used then 2 + 1 = 3 even though 2 had been deleted.
Using AUTOINCREMENT is inefficient as to know what the last used value was requires a system table, sqlite_sequence and it being accessed to store the latest id and also to retrieve the id.
The SQLite AUTOINCREMENT documentation, says this:-
The AUTOINCREMENT keyword imposes extra CPU, memory, disk space, and disk I/O overhead and should be avoided if not strictly needed. It is usually not needed.
There are other differences, such as with AUTOINCREMENT if the id 9223372036854775807 has been reached, then another insert will result in an SQLITE_FULL error. Whilst without AUTOINCREMENT then an unused id (there would be one as current day storage devices could not hold that number of rows).
The intention of id's (rowid's) is to uniquely identify a row and to be able to access such a row efficiently if accessing it by the id. The intention is not for it to be used as a sequence/order. Using it as a sequence/order number will probably invariably result in unanticipated sequences or inefficient overheads trying to maintain such a sequence/order.
You should always consider that rows are unordered unless specifically ordered by a clause that orders the output, such as an ORDER BY clause.
However, if you take your example a little further, omitting AUTOINCREMENT, will still probably result in the order/sequence issues as if, for example, the row with an id of 1 were deleted instead of 2 then you would end up with id's of 2 and 3.
Perhaps consider the following which shows a) how the limited issue you have posed, is solved without AUTOINCREMENT, and b) that it is not the solution if it is not the highest id that is deleted:-
DROP TABLE IF EXISTS sample1;
CREATE TABLE IF NOT EXISTS sample1( name TEXT, id INTEGER PRIMARY KEY);
INSERT INTO sample1 VALUES ('ROY',1);
INSERT INTO sample1(name) VALUES ('RAJ');
DELETE FROM sample1 WHERE id = 2;
INSERT INTO sample1 VALUES ('AMIE',NULL);
/* Result 1 */
SELECT * FROM sample1;
/* BUT if a lower than the highest id is deleted */
DELETE FROM sample1 WHERE id=1;
INSERT INTO sample1 VALUES ('EMMA',NULL);
/* Result 2 */
SELECT * FROM sample1;
Result 1 (your exact issue resolved)
Result 2 (if not the highest id deleted)

Continue with Id order values after delete some rows

I accidentally deleted some rows from a table, it's just 4 rows, but now when I try to insert the same values again the Id values are different, it's like it's remembering the Id values that had the rows I deleted before and now every time I insert a row the value generated for Id is not the next to the existent sequence... For example:
Id Name
1 Peter
2 Luis
3 Charles
4 John
Let's say I deleted rows with Name value Peter, Luis, Charles and John. When I try to insert the same names again it inserts them but with a different Id..
Id Name
1 Peter
5 Luis
6 Charles
7 John
I can not change the Identity value manually to the old values.. Which is the best solution in this case?
The reason is that auto-incrementing Id's don't automatically reset. This is by design, as you may have the same values references in other tables, which you may not want to delete (although it creates orphaned rows).
The method of resetting the auto-incrementing value differs between databases. For instance, in MySQL, you can run:
ALTER TABLE myTable SET AUTO_INCREMENT=1;
If you AUTOINCREMENT the Primary Key then you can't change the sequence with which you have started.Even if you insert the same name again it does not matter.It will continue from the next number with which it previously ended.
But if you want to give it a number then don't AUTOINCREMENT it,INSERT primary key value like other values you have inserted in the table.
I ended up setting identity_insert to on and entering the Ids manually with the names and then changed the table back to how it was with identity_insert off

Is it possible to insert data into table using two select statements in one query?

I am working with databases in which I have 3 tables one is skill table the other one is experience and the third one is Experience_skill table in this table I have foreign keys now the question is both foreign keys are primary keys as well. Let say I am storing data into skill table as well as in experience table how can I insert the the both keys data there in Experience_skill table. I have tried following queries.
insert into Experience_skill(eid, Skill_Id)
select eid
from Experience
where eid=2
union
select Skill_Id
from Skills
where Skill_Id=2
error I get:
The select list for the INSERT statement contains fewer items than the insert list. The number of SELECT values must match the number of INSERT columns.
Than i tried this one.
insert into Experience_skill(eid)select eid from Experience where eid=2
it gives me this error:
Cannot insert the value NULL into column 'Skill_Id', table 'resume.dbo.Experience_skill'; column does not allow nulls. INSERT fails.
Please help me out
here are the snapshots of the table first snap shot is of skill table
the second one is experience table
And this one is EXperience_skill table where i have my foreign keys
When using INSERT INTO, you need to supply ALL of the columns in the destination table (that do not allow NULLs) in each ROW of the SELECT.

Updating database records with unique constraint

Given the following simple table structure (SQL Server 2008), I want to be able to maintain uniqueness of my numerical sequence column, but I want to be able to update that value for any given record(s).
CREATE TABLE MYLIST(
ID int NOT NULL IDENTITY(1, 1)
, TITLE varchar(50) NOT NULL
, SEQUENCE int NOT NULL
, CONSTRAINT pk_mylist_id PRIMARY KEY(ID)
, CONSTRAINT uq_mylist_sequence UNIQUE(SEQUENCE)
);
My interface allows me to jumble up the order of the items and I will know prior to doing the update which non-overlapping sequence they should all be in, but how do I perform the update without being confronted with a violation of the unique constraint?
For instance, say I have these records:
ID TITLE SEQUENCE
1 APPLE 1
2 BANANA 2
3 CHERRY 3
And I want to update their sequence numbers to the following:
ID TITLE SEQUENCE
1 APPLE 3
2 BANANA 1
3 CHERRY 2
But really I could be dealing with a couple dozen items. The sequence numbers must not overlap. I've thought about trying to use triggers or temporarily disabling the constraint, but that would seem to create more issues. I am using C# and LINQ-to-SQL, but am open to strictly database solutions.
The obvious way is to write as one batch. Internally, SQL will defer the constraint checks so intermediate uniqueness is irrelevant.
Writing row by row does not make sense and causes the problem you have.
You can change this to write into a temp table, and then "flush" the results at the end, even check uniqueness over the temp table first.
DECLARE #NewSeq TABLE (ID int, NewSeq int)
INSERT #NewSeq (ID, NewSeq) VALUES (1, 3)
INSERT #NewSeq (ID, NewSeq) VALUES (2, 1)
INSERT #NewSeq (ID, NewSeq) VALUES (3, 2)
UPDATE
M
SET
SEQUENCE = NewSeq
FROM
MYLIST M
JOIN
#NewSeq N ON M.ID = N.ID
You could assign them the negative of their correct value, then after all updates have occurred, do a final update where you set SEQUENCE = -SEQUENCE.
It is not very efficient, but since you say you only have a couple dozen items, I doubt the impact would be noticeable. I am also assuming that you can use negative numbers as "magic values" to indicate temporarily mis-assigned values.
If you really have to follow that workflow of inserting without knowing the right order and then having to come back with an update later to set the right order, I'd say your best option is to get rid of the unique constraint because it is causing you more problems than it is worth. Of course, only you know how much that unique constraint is "worth" to your application.

Filling the gaps in values of IDENTITY column

I have a table with an IDENTITY column
[Id] int IDENTITY(1, 1) NOT NULL
After some rows beeing added/removed I end with gaps in Id values:
Id Name
---------
1 Tom
2 Bill
4 Kate
Is there an easy way to compress the values to
Id Name
---------
1 Tom
2 Bill
3 Kate
?
I would strongly recommend that you leave the identity values as they are.
if this ID column is used as a foreign key on another table, changing them will get complicated very quickly.
if there is some business logic where they must be sequential then add a new column ID_Display where you can update them using ROW_NUMBER() and keep them pretty for the end user. I never let end users see and/or dictate how I create/populate/store the data, and if they are bothering you about the IDs then show them some other data that looks like an ID but is not a FK or PK.
I think it's pretty easy to create a 2nd table with the same schema, import all the data (except for the identity column of course; let the 2nd table start renumbering) from the first table, drop the first table and rename the 2nd to the original name.
Easiness may be in question if you'd have a ton of FK relationships to rebuild with other tables etc.
Well as far as I know the only way you can is manually update the values by turning Identity insert on..but you should really avoid doning such a thing in first place..also if you truncate the table it will not have those gaps.
I cannot control the part which requires ID columns to be in sequence.
This sounds like there is program logic which assumes there are no gaps--correct?
I need this to keep two different databases in sync.
It's still not clear what you mean. If the actual values in the IDENTITY column are not meaningful (not used as foreign keys by other tables), you can just do this:
DELETE FROM db1.table
SELECT col1, col2, col3 /* leave out the IDENTITY column */
INTO db1.table FROM db2.table