I have joined a project which has used client side generated random numbers for primary key fields within a mysql database. These primary key fields are auto-increment, but have not been used as such.
I think this was done because the developer did not know how to retrieve the database generated id after insertion.
We now have a sparse array of id values in many tables and a significant number of key collisions on insertion.
Is there some remedial work I can do to allow the database to generate the ids (i.e. start from the last allocated id and find the next available id) and for the following JDBC call to work?
numero = stmt.executeUpdate(query, Statement.RETURN_GENERATED_KEYS);
I think if you search Google for 'generate database primary key from sequence MySQL' it will help.
Using sequences: Find the largest primary key in a given table, and create a sequence that increments by 1, starting with that largest primary key value. Create a separate sequence for each table. Note your are letting the database generate the key so you will have to disable the program or client from generating the key.
Alternately, you can create a brand new database schema that implements primary key generation correctly. Then migrate the data from the old database to the new one, populating parent tables before the child tables. Then, programmatically matching parent to child records based on the old priamry keys. However, I think this will be very time consuming for the size of your database.
Related
I'm working on a Java project which needs to be able to alter all the primary keys in a table - and in most cases - some other values in the row as well.
The problem I have is that, if I update a row by selecting by its old primary key (SET pk=new_pk WHERE pk=old_pk) I get duplicate rows (since the old PK value may be equal to another row's new PK value and both rows are then updated).
I figured that in Oracle and some other DBs I might be able to do this with ROWNUM or something similar, but the system should work with most DB systems and right now we can't get this to work for MySQL.
I should add that I don't have access to change the schema of the DB - so, I can't add a column.
What I have tried:
Updating ResultSets directly with RS.updateRow() - this seems to
work, but is very slow.
Hashing the PK's in the table, storing the hash in code and selecting on the hashed PK. This acts sort of as a signature, since a
hashed PK indicates that the row has been read but not yet updated
and I can avoid appropriate rows that way. The issue with this seems
to have been hash collisions as I was getting duplicate PKs.
PS:
I realise this sounds like either a terrible idea, or terrible design, but we really have no choice. The system I'm working on aims to anonymize private data and that may entail changing PKs in some tables. Don't fear, we do account for FK references.
In this case you can use simple update with delta = max Pk from updating table
select delta
select max(pk) as delta from table
and then use it in query
update table SET pk=pk+delta+1
Before this operation you need to disable constraints. And don't forget that you should also update foreign keys.
I am using a postgresql database table which may have inserts with the ID set manually by the user, or need an ID generated using hibernate.
This may lead to the occurrence of generating an ID which has already been inserted into the database manually. Is there any way hibernate can check for collisions between the generated ID and existing IDs?
Hibernate cannot check that, because the sequence is allocated by the database. You could either:
assign negative numbers for manually inserted IDs
use UUID instead of sequences
So I have a MySQL database schema where there is a USERS table which contains the ID as a primary key for that table, I also have a USER_PASSWORDS table which references the USERS table where the USER_ID will act as a foreign key in this table.
The issue that I am facing is that I am writing an application where the user will be able to sign up and specify a username and password. But I would like to insert the user into the database with one query.
I was thinking I had to insert the username first into the USERS table and see what ID has been given to that username and then insert the hash of the password that the user has entered into the USER_PASSWORDS table and specifying the ID that was queried.
I dont like this approach because it means that I have to:
INSERT into the database
QUERY the database
INSERT into the database again
Is there a better way of doing this?
Thanks
You can't insert into two tables with one insert statement, and you would have to query the users table anyway to get the ID value to insert as a foreign key for the user_passwords table.
Really the only way to do what you want is the solution you've already identified:
Insert into the Users table
Query to get the ID of the User you just inserted
Insert into the USER_PASSWORDS table with the ID you obtained for the User.
You could wrap all this up in a stored procedure that takes user data and password as parameters, which would be the "better" way of doing it.
As you didnt really tell for what system / programming language you need this and you did not provide any code example either, I can only give you some theory what you could do:
Its impossible to insert data into two different MySQL tables with one queries but you can reduce your script atleast by the SELECT query:
1.) There is a function in most mysql apis (Depending on what programming language and MySQL Library you are using) that says "getLastInsertId()", "lastInsertId()" or similar.
This will return the ID that was inserted by the auto-increment of the table after the insert is completed.
Just check the docs of your MySQL-api it will have such a function.
2.)
The second possibility is using a UUID - a very large (commonly 128-bit) long string which is generated totally random. There are more so many possible combinations it will happen more probably that you win in the lottery 10 times in a row then you generate two times the same UUID that is already in your table.
So you just generate the UUID and insert it as a key in both tables and you are done.
Just use google to find out-of-the-box libraries to generate UUID's you dont need to build the alogrithm on your own.
An UUID could looks like this:
4a34fe87-f577-4ea9-9557-1bc8f779a68c
One solution: since the hash is unique you can use the hash as a primary key in the USERS table. Then you know what the primary key (id) is at the time of the insert and can reuse when INSERTING in the USER_PASSWORDS table.
That way you can avoid the id query at least.
I'm working on a servlet that needs to insert some data to the db table with a composite primary key consists of the userid, dataid and CURRENT_TIMESTAMP.
however im getting the following error when executing the query
com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry'13-7-2013-09-13 23:22:24' for key 'PRIMARY'
I think this is caused by the multiple insertion of rows to the same table in the same time, though with different dataid. Is there any solution to this problem? Should I cancel CURRENT_TIMESTAMP as a part of the primary key to do the trick or there are some other better workarounds?
Thanks a lot and appreciate for any help!
If it's a log table, it is recommended not to use a primary key. If you want to accelerate some search in this table, create the appropriate indexes.
If you need a primary key (for example, if you plan to use it with JPA), it would be best to use a number, e.g.
ID int AUTO_INCREMENT PRIMARY KEY
For example, log4j can insert each event log into a database using a org.apache.log4j.jdbc.JDBCAppender.
See also MySQL storage engine for a large log table.
I want to get surrogate keys for my user table(s) in MySQL. I'm sure concatinating an incrementing value + a timestamp would get me unique keys across multiple tables but how do I get the incremental value for the class's persistence table before I persist it to the database.
let hibernate do it for you using one of their key generators. If you must define your own key scheme, you will have to write your own generator.