The problem
I have a table for some data that has an ID column of type integer (which is also the primary key).
When a new data entry is added to the table, it should get a new ID whereas the ID is not known by the application that inserts the object but it should be given by the database. For example, the IDs should be assigned like 0, 1, 2, ...
Assume that I have all other data for the new entry, how would I do the insert? Normally:
insert into T values(123, 'data');
But now I don't know what to put instead of 123
- would you create some kind of global variable NEXTID in the database that provides the IDs and query/update this value each time before inserting into T?
The questions
How to handle this kind of problem? A solution that is concurrency save is preferable.
How to achieve this with Java/myBatis? I Have a Java class that corresponds to the table structure and a new object should be added to the database, getting a new ID automatically.
Update
What I searched for was auto-increment.
Is there a standard SQL way (database independent) of declaring a column as auto-increment? I am using Apache Derby and GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1) is suggested here.
How does the insert to a table that contains auto-increment columns look like?
What is the best way to get the created auto-increment value after an insert when simultaneaous access to the database is possible?
I'll accept an answer that includes explanation and SQL instructions for declaration and insertion :)
If you are using sqlserver, making column of identity type will solve the purpose something like this
.
ALTER TABLE [dbo].[T] ADD [Column1] INT identity (1, 1)
For others like oracle you can for simple database sequence.
In MySQL you can use
ALTER TABLE table_name ADD id INT AUTO_INCREMENT;
this auto increment the id column, you don't have to give in insert.
Related
so I created a table with a column which I declared EmployeeID as a primary key int with auto increment, but here is the problem:
If I delete a row and then insert a new one the new increment will still count
For example:
ID Name
1 jayden
2 karen
delete karen ...
ID Name
1 jayden
insert new one
ID Name
1 jayden
3 nicolas
So it basically skips the previous ID.
This is not a mistake, it is how MySQL works with auto_increment. It stores the last value which it gave at the insertion and increments it. You can always get the last ID at your next insertion
insert into yourtable(id, Name)
select id + 1, 'foo'
from yourtable
where id = (select max(id) from yourtable);
That's because an auto increment is a independent property of your table, that is only used when assigning new IDs and does not depend on the last existent ID on your table. This is how many relational databases, not only MySQL, were designed for.
To achieve what you want (which seems to be having IDs in sequence without "holes") you would need to query the last ID and increment on it to be set manually.
Ex:
SELECT id from Users ORDER BY id DESC LIMIT 1
Or instead setting the auto_increment of your table according to your last id.
Be aware that both of this is not performatically wise. You should really stick to the auto increment default behavior, since it's optimal, unless you have some strong reason for not doing things as they were designed to be done.
This is expected behavior from the 'delete' command
What would you ever want/need an Unique Identifier that can be reaffected to someone else?
The 'Truncate' command will delete all your data and reset the ID, maybe this is what you are looking for
After delete a row use this query,
ALTER TABLE tbl_name AUTO_INCREMENT = ID;
Actually this is how MySQL works and it's not a mistake
I am unable to grasp the concept of the lookup table.
I am currently working on a project wherein I am using two tables.
The first table consists of two columns- name(varchar) and value(varchar).
The second table also has two rows- Result(varchar) and value(varchar).
Result is used to store the values which are obtained from a Java code. Whenever the Result of the Java code matches the name in the first table, I need to update the second table with the corresponding value in the first table.
Does using lookup table help in any way? If it does, can it be explained with an example?If not, is there any other way?
Just imagine a table person with a column GenderIsMale BIT. You can set this value to 1 (yes, it is a boy) or to 0 (no, a girl). This was easy in earlier days.
Now we have more categories. According to this link facebook offers more than 50 differing categories...
There the lookup-table comes into play: You create a table which has - as minium - a unique key and a value. In most cases this is an ID INT IDENTITY and a Content VARCHAR(100) NOT NULL. You can add more columns like Abbreviation or any other additional content (e.g. other languages or codes of external code systems read about mapping tables also) directly bound to this value.
The next step is, to take the GenderIsMale-column away and replace it with a
GenderID INT NOT NULL
CONSTRAINT FK_Person_GenderID FOREIGN KEY REFERENCES GenderLookUpTable(GenderID)
The person table will store the GenderID only, the related values are stored in the side table and can be looked up.
The simple lookup table is the basic construct of how to create a relational database model in min. 3.NF or BCNF (which should be a minium reuqirement for professional database design).
Whenever the Result of the Java code matches the name in the first
table, I need to update the second table with the corresponding value
in the first table.
That's a perfect use case for database trigger, which can be used to perform various things when a change (insert, update, delete) happens in a table.
Assuming you're inserting the value of your Java calculations to your (result, value) table (let's call it foo, and the other table is bar), you can write a trigger that replaces the value being written with the value from the other table. Example given for Postgres, if using another db refer to your particular RDBMS manual to see the syntax.
CREATE FUNCTION get_value_from_lookup_table() RETURNS trigger AS $$
BEGIN
IF EXISTS (SELECT 1 FROM bar WHERE name = NEW.result) THEN
RETURN SELECT name, value FROM bar WHERE name = NEW.result;
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER lookup_value
INSTEAD OF INSERT ON foo
FOR EACH ROW
EXECUTE PROCEDURE get_value_from_lookup_table();
Every time an INSERT is done on foo, a check is done to see if a row exists in bar where name=result. If so, that row is inserted, otherwise the insert goes on normally. That's the basic gist of it. The actual solution depends on table constraints, whether you need to handle inserts and updates, etc.
I have mentioned a sequence generation strategy as IDENTITY on my entity class for the primary key of a table in AS400 system.
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name = "SEQNO")
private Integer seqNo;
The table's primary key column is defined as GENERATED ALWAYS AS IDENTITY in database.
SEQNO BIGINT NOT NULL GENERATED ALWAYS AS IDENTITY(START WITH 1, INCREMENT BY 1)
My understanding of IDENTITY strategy is that it will leave the primary key generation responsibility to the table itself.
The problem that I am facing is that somehow in one environment, while inserting record in the table it gives me [SQL0803] Duplicate Key value specified.
Now there are couple of questions in my mind:
Is my understanding correct for #GeneratedValue(strategy=GenerationType.IDENTITY)?
In which scenario table will generate Duplicate key?
I figured out there are sequence values missing in the table, i.e. after 4, the sequence till 20 is missing and I do not know if someone manually deleted it or not, but could this be related to duplicate key generation?
YES. IDENTITY means use in-datastore features like "AUTO_INCREMENT", "SERIAL", "IDENTITY". So any INSERT should omit the IDENTITY column, and will pull the value back (into memory, for that object) after the INSERT is executed.
Should never get a duplicate key. Check the INSERT statement being used.
Some external process using the same table? Use the logs to see SQL and work it out.
I don't use JPA, but what you have seems reasonable to me.
As far as the DB2 for i side...
Are you sure you're getting the duplicate key error on the identity column? Are there no other columns defined as unique?
It is possible to have a duplicate key error on an identity column.
What you need to realize is that the next identity value is stored in the table object; not calculated on the fly. When I started using Identities, I got bit by a CMS package that routinely used CPYF to move data between newly created versions of a table. The new version of the table would have a next identity value of 1, even though there might be 100K records in it. (the package has since gotten smarter :) But the point remains that CPYF for instance, doesn't play nice with identity columns.
Additionally, it is possible to override the GENERATED ALWAYS via the OVERRIDING SYSTEM VALUE or OVERRIDING USER VALUE clauses of the INSERT statement. But inserting with an override has no effect on the stored next identity value. I suppose one could consider CPYF as using OVERRIDING SYSTEM VALUE
Now, as far as your missing identities...
Data was deleted
Data was copied in with overridden identities
Somebody ALTER TABLE <...> ALTER COLUMN <...> RESTART WITH
You lost the use of some values
Let me explain #4. For performance reasons, DB2 for i by default will cache 20 identity values for a process to use. So if you have two processes adding records, one will get values 1-20 the other 20-40. This allows both process to insert concurrently. However, if process 1 only inserts 10 records, then identity values 11-20 will be lost. If you absolutely must have continuous identity values, then specify NO CACHE during the creation of the identity.
create table test
myid int generated always
as identity
(start with 1, increment by 1, no cache)
Finally, with respect to the caching of identity values. While confirming a few things for this answer, I noticed that the use of ALTER TABLE to add a new column seemed to cause a loss of the cached values. I inserted 3 rows, did the alter table and the next row got an identity value of 21.
I have a table "groups" with four columns. The database is postgres and the group_id column is a Serial. So in reality it is an Integer with a default to get the next value.
I have a use case where I need to use #SQLInsert (using the normal persist method is not an option), but I can't get it to work with the default. Here is what I have:
#SQLInsert(sql="INSERT INTO groups (group_id, parent_id, group_name, version) VALUES (DEFAULT,?,?,?)")
I set the entity attributes to values where group_id and version are null, and the other two are correctly populated. group_id is not nullable in the DB, version can be null.
I get this exception:
WARNING: SQL Error: 0, SQLState: 22023
SEVERE: The column index is out of range: 4, number of columns: 3.
SEVERE: Could not synchronize database state with session
If I enter the following DML directly on the database, it works:
INSERT INTO groups (group_id, parent_id, group_name, version) VALUES (DEFAULT, 3, 'abcd', null);
Is there some way to make the same thing happen using #SQLInsert.
If the class members which you want to save are not reference types they can not hold a null value. It may be the cause of failure in synchronization with database records. Try to use reference types like Integer and Double, etc. And get sure that default values are assumed with a direct insert query.
Another thing in your error messages. It may the default value is out of boundary of the type you are using in Java for that column. Check the default value to be in range. If a value out of range is set for your class member, it can't be synced.
EDIT: Sorry, the second part is not true in this case.
So the short answer is "it can't be done this way". Despite quite a few places I've seen this asked, the Hibernate people have not provided for this use case.
My solution was to decouple the Postgres sequence from the table. That is, I removed the default constraint that selects the nextval from the sequence and populates one of the two primary key fields.
I then manually grab the nextval using a native query (yep, forced to un-abstract the database), and use that value to manually populate the primary key field. It works. It's kludgy, but I might use it more often. It certainly is a lot more understandable as to what is happening than using the pure ORM methods. This can be debugged without a wizards hat. :)
public class...
#PersistenceContext(unitName = "persistence_unit")
private EntityManager em;
...
mymethod(){
...
Query q = em.createNativeQuery("SELECT nextval('groups_group_id_seq')");
BigInteger groupId = (BigInteger)q.getSingleResult();
BigInteger parentId = methodToGetParentId();
GroupsPK gpk = new GroupsPK(groupId, parentId);
Groups grps = new Groups(gpk, "other parameters");
...
}
I'm trying to do a comparison between the data of a table of a SQLServer database before and after some action.
I'm saving the first data in a file (actually I'm saving the MD5 of the data, but not relevant), so I can compare the new data with it after the action.
The first problem is that the data returned by the query is not always in the same order.
So to solve this problem I thought about using the ORDER BY clause to order the data.
Here comes the second problem. I'm executing a query defined by the user, so the query, and the table may be different.
So here is the question: How can I ORDER BY the PRIMARY_KEY (one or multiple) without previous knowledge of what table will be used??
Any other solution will be also welcomed,
Thanks for your time and effort,
You can use dynamic sql and query the meta tables to discover what the primary key is
SELECT column_name
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
WHERE OBJECTPROPERTY(OBJECT_ID(constraint_name), 'IsPrimaryKey') = 1
AND table_name = 'Person'
With dynamic sql you construct your sql statement like a string and hand it over to sp_executeSQL
More info at http://msdn.microsoft.com/en-us/library/ms188001.aspx
I'm trying to do a comparison between the data of a table of a
SQLServer database before and after some action.
If you are using SQL Server 2008, you can use CDC
Do you really need to order by the primary key? If not you can do
ORDER BY 1, 2, 3
that will order by column 1, 2 and 3 regardless the name of the column.
That would work on the PK if you have your Primary key on the first column of the table