Suppose you have a database with an auto-incrementing primary key and 25 records (PK goes from 1 to 25). Delete the record whose PK=25; PK values will now go from 1-24. Finally add a new record. Its PK value will be 25.
This would be quite problematic if other tables used the value 25 as a foreign key. They would would be linked to an erroneous record.
How is this issue customarily addressed?
In almost all databases, once allocated, the auto increment value will not be reused even if the original row is deleted.
There is an exception in SQLite if you rely on the built-in ROWID value rather than declaring a column to be AUTOINCREMENT. In the second case, things work as you expect (values are never recycled). In the first case, however, in the situation you describe (deletion of highest-numbered row), the value will be recycled.
But consider that in the case which you describe where the ROWID is used as a primary key and all other references are protected with an enforced foreign key relationship then, in order to delete the record with value 25, all references to it must first be removed from the database.
The problem only occurs when you have non-enforced references to the primary key value.
Nonetheless, I think it's a best practice to explicitly declare the primary key to be AUTOINCREMENT. A counter-argument can be read here: http://www.sqlite.org/autoinc.html.
Can you use uniquidentifiers? I suggest if you are not constrained.
Related
I needed to modify by a datatable by setting the id column as the PRIMARY KEY in order to work with it on a client I am developing. However, I forgot to copy/screen-cap the already existing records and now I get the feeling data is missing. Was it possible that setting a column as the primary key could've affected data in other columns?
FYI, I set the primary key by going into the design, right clicking the column, and clicking on "Set as primary key"
What 'design' tool were you using? The only thing that would make sense would be if there were duplicate ids, but that should give an error instead of picking random rows. The only other thing I can think of would be if you had a foreign key set to cascade deletes and deleted rows in the child table.
You only say you have an 'idea' that rows were deleted. That makes me think that you might be just doing some simple 'select top(100) *' query or something and don't see the same data as you had before, i.e. you used to see ids like 2093939 and now you only see 1, 2, 3, etc.
When creating a primary key or a clustered index, that can alter the order that rows are returned by default. Creating a clustered primary key would most likely then return the rows in ascending order in that case by default. Could this be the case?
I want Write ALTER TABLE SQL statement to add a column to the table. The column is classified as NUMBER datatype, NOT NULL attribute, and primary key.
But it shows ORA-01758.
ALTER TABLE INSURANCE
ADD (INS_ID NUMBER PRIMARY KEY NOT NULL);
If I select DEFAULT 0, it really solves the problem, but I cannot set up a primary key and INS_ID shows 0, not (null)
Because this table's data is from a excel document, what should I solve it without delete data?
If I must delete data how restore it easily?
Typically you can either:
provide a default value so oracle can fill the column as it creates, satisfying the constraint or
create the column as nullable, fill it with relevant data, then enable the not null restriction/make it the primary key after it has data or
empty the table
1 is not an option for you, because the values will have to be unique if they are to be a primary key. You could consider associating the column with a sequence or making it an identity column though
2 is a likely option for you if an auto generated incrementing number is no good as a PK (for example the key data is already known or calculated)
3 is something you've already said is not an option
Give some thought to the ongoing maintenance requirements - every front end app that writes data into this table will need to be upgraded to understand it has a primary key unless you're using a sequence/identity or similar that provides a unique value for the row. If there will be a lot to update and you dont care to have a PK in a particular form or from some existing value/relationship elsewhere, having an auto number PK can be helpful. If this data needs to relate to existing data that has a key, you need to upgrade front end apps so they can respect the new PK
I am having trouble answering the following question...
Illustrate by an example a scenario where an attribute has unique values in the different rows, yet it can’t be used practically as a primary key in the database relations/tables.
If the suggested column that has unique values is nullable and contains null values too, it cannot be a practical primary key. Because primary keys can't be null.
A non-sequential GUID is a bad candidate for a primary key, when the data is stored ordered by that key. An insert of a new row will not be appended to the table but must be inserted in the middle, meaning that data must be moved around to make room.
That is why there may also exist sequential GUIDs .
"random" is unique but practically as a key I would not use it.
Assume that I know that updating a primary key is bad.
There are other questions which imply that the inserted and updated table records match by position (the first of one matches the first of the other.) Is this a fact or coincidence?
Is there anything that could join the two tables together when the primary key changes on an update?
There is no match of inserted+deleted virtual table row positions.
And no, you can't match rows
Some options:
there is another unique unchanging (for that update) key to link rows
limit to single row actions.
use a stored procedure with the OUTPUT clause to capture before and after keys
INSTEAD OF trigger with OUTPUT clause (TBH not sure if you can do this)
disallow primary key updates (added after comment)
Each table is allowed to have one identity column. Identity columns are not updateable; they are assigned a value when the records are inserted (or when the column is added), and they can never change. If the primary key is updateable, it must not be an identity column. So, either the table has another column which is an identity column, or you can add one to it. There is no rule that says the identity column has to be the primary key. Then in the trigger, rows in inserted and updated that have the same identity value are the same row, and you can support updating the primary key on multiple rows at a time.
Yes -- create an "old_primary_key" field in the table you're updating, and populate it first.
Nothing you can do to match-up the inserted and deleted psuedo table record keys -- even if you store their data in a log table somewhere.
I guess alternatively, you could create a separate log table that tracked changes to primary keys (old and new). This might be more useful than adding a field to the table you're updating as I suggested right at first, as it would allow you to track more than one change for a given record. Just depends on your situation, I guess.
But that said -- before you do anything, please go find a chalk board and write this 100 times:
I know that updating a primary key is bad.
I know that updating a primary key is bad.
I know that updating a primary key is bad.
I know that updating a primary key is bad.
I know that updating a primary key is bad.
...
:-) (just kidding)
I am using GUIDs as my primary key for all my other tables, but I have a requirement that needs to have an incrementing number. I tried to create a field in the table with the auto increment but MySql complained that it needed to be the primary key.
My application uses MySql 5, nhibernate as the ORM.
Possible solutions I have thought of are:
change the primary key to the auto-increment field but still have the Id as a GUID so the rest of my app is consistent.
create a composite key with both the GUID and the auto-increment field.
My thoughts at the moment are leaning towards the composite key idea.
EDIT: The Row ID (Primary Key) is the GUID currently. I would like to add an an INT Field that is Auto Incremented so that it is human readable. I just didn't want to move away from current standard in the app of having GUID's as primary-keys.
A GUID value is intended to be unique across tables and even databases so, make the auto_increment column primary index and make a UNIQUE index for the GUID
I would lean the other way.
Why? Because creating a composite key gives the impression to the next guy who comes along that it's OK to have the same GUID in the table twice but with different sequence numbers.
A couple of thoughts:
If your GUID is auntoincremental and unique, why not let it be the actual Primary Key?
On the other hand, you should never take semantical decisions based on programmatic problems: you have a problem with MySQL, not with the design of your DB.
So, a couple of workarounds here:
Creating a trigger that would set the GUID to the proper value once it's inserted. That's a MySQL solution to a MySQL problem, without altering semantics for your schema.
Before inserting, start a transaction (make sure auto commit is set to false), find out the latest GUID, increment and insert with the new value. In other words, auto-increment not automatically :P
GUID's are not intended to be orderable, that's why AUTO_INCREMENT for them does not make sense.
You may, though, use an AUTO_INCREMENT for a second column of a composite primary key in MyISAM tables. You can create a composite key over (GUID, INT) column and make the second column to be AUTO_INCREMENT.
To generate a new GUID, just call UUID() in an INSERT statement or in a trigger.
No, only the primary key can have auto_increment as its value.
If, for some reason, you can't change the identity column to be a primary key, what about manually generating the auto-increment via some kind of SEQUENCE table plus a trigger to query the SEQUENCE table and save the next value to use. Then assign the value to the destination table in the trigger. Same effect. The only question I would have is whether the auto-incremented value is going to make it back thru NHibernate without a re-select of the table.