I have a table xxx with id (id_xxx int AUTO_INCREMENT ) and name (name_xxx varchar (50)),
When I insert a new row in the table I made:
INSERT INTO xxx VALUES ("name for test");
and the result (int=1) of insertion is returned, then I display in my java interface a message "succseed!", until now it's a very basic and simple operation...
BUT,
when I want to return the inserted id_xxx,I have to do another query to the database:
INSERT INTO xxx VALUES ("name for test");
//after the insert response I made:
SELECT MAX (id_xxx) FROM xxx;
and I display in my java interface "succseed $$$ is your id_xxx "....
the second version can easily cause a serious error during concurrent access to multiple users:
imagine a case when a user1 makes an insert... and then H2DB interrupt operations of this user then executes the insert of user2.
when user1 executes a select max (id_xxx) the H2DB return A FALSE id_xxx...
(I hope that my example is clear otherwise I will schematize this problem).
how to solve this problem?
You should be able to retrieve keys generated by insert query, see 5.1.4 Retrieving Automatically Generated Keys.
Related
Say I have a table named users and a column named username with the format user1, user2 ..
I want to insert users into this table in a loop and value of every entry depends on the one's before. Value of the new entry is generated by the alphabetically greatest entry in the table, namely users.
Since it's possible in JDBC API to getGeneratedKeys after an insert while AutoCommit set to false;
In a situation like given below:
connection.setAutoCommit(false);
while(someCondition)
{
ResultSet rs = connection.createStatement("select max(username) from users").executeQuery();
if(rs.next())
{
name= rs.getString("username"); //returns user1
}
String newName = generateNewName(name); // simply makes user1 -> user2
connection.createStatement("insert into users (name,...) values ("+newName+",...)").executeUpdate(); ///and inserts..
}
does the select query return the last inserted value
or
it returns the max column in the table before I start the loop ?
First, to make sure you see all changes on the database immediately prefer TransactionIsolation of READ_UNCOMMITED over using auto commit. Alternatively using auto commit everywhere would do the job, too.
Once you made sure you see every db change immediately, the database will send you the maximum user from some time during the selects execution. But once you actually receive the result there might be additional users created by others threads. Thus this will only work for a single thread working and most likely that doesn't make any sense nowadays.
TL:DR
No, don't do it!
Hello guys I need fill a table with el result of my query like....
SELECT FIELD1, FIELD2, X FROM OLDTABLE WHERE X=Y
I am a Java developer, my friends, RPG developers in the AS400. When they execute a a Query have a option to save the query result in a file
The option is called SELECT output and can choice 1 Display 2 Printer 3 File
Can do this directly from a query? or is a native iSeries option ?
Create a table with iseries sql
create a table with data.
create table abc as (select x,y,z from sometable where x=y) with data
create an empty table.
create table abc as (select x,y,z from sometable where x=y) data definition only
There is no output to printer using just sql.
Query will prompt you to replace an existing table. Straight SQL won't prompt to replace an existing table so you have two scenarios (see note) .
If the output table doesn't exist, all you need is
create table newtable as (select <...> from oldtable) with data
If the output table already exists, all you need is an insert with sub-select.
Insert into newtable
Select <...> from oldtable
NOTE
With the release of TR10 for v7.1 and TR2 for v7.2 in May 2015, IBM has added support the OR REPLACE clause to the CREATE TABLE statement. So if you happen to be on those TRs or higher, you could simply use:
create or replace table newtable as (select <...> from oldtable) with data
Could compile the SQL into a query manager query (CRTQMQRY) then run the query via (STRQMQRY).
To do that, put the query into the some sort of source file with a member type of TXT. Get to a command line and run the CRTQMQRY command and create the output QMQRY. STRQMQRY can be prompted and you can save the results in either an output file or a printout or look at it interactively. If you submit it as a batch job, viewing the output interactively won't work too well.
DELIMITER $$
CREATE TRIGGER `classdost`.`tr_xyz_media`
BEFORE INSERT ON classdost.xyz_media
FOR EACH ROW
BEGIN
DECLARE t_id INT(20);
IF NEW.id < 5000000 THEN
INSERT INTO xyz_media_temp (insert_date) VALUES(CURDATE());
SELECT MAX(xyz_media_temp.id) INTO t_id FROM xyz_media_temp;
SET New.id = t_id;
END IF;
END$$
DELIMITER ;
I have this trigger in MySQL this is running fine when I fire any Insert query in PHPMyadmin but when same Insert is fired from java code it is not executing. I tried changing the code made all request as Ajax with async: false and then I found out that that the earlier requests are still running in background and my later request is giving exception as no ID is returned from database yet.
What can be done to avoid this issue?
If you say requests are still running in background, then it is possible that your table is locked (MyISAM tables), and you cannot modify it.
See if table is locked using this query -
SHOW OPEN TABLES FROM database_name;
This query will show you open tables, whicj cannot be edited (INSERT, UPDATE or etc.). Then check you Java application, find code that locks tables.
Let me give the example first. It is a log table.
User A subscribe the service A = OK
User A unsubscribe the service A = OK
User A subscribe the service A again = OK
User A subscribe the service A again = Not OK, because you can't subscribe same service at the same time.
Sometimes the client goes crazy and send 5 subscribe requests at the same time ( 4 tomcat servers behind), if I do nothing in this situation then 5 same records will be inserted.
As you can see, I can't use unique constraint here.
I guess perhaps I can use some single thread block in Oracle, but not sure..
I tried "merge" , but I guess it is used in specific records instead of last record.
begin single thread
select the last record
if the last record is the same then don't insert.
if the last record is not the same then insert.
end single thread
Is it possible and how to achieve ?
Perhaps you need to check for the user id, and service type. if same user trying to subscribe same service before the previous subcribed service is performed, then alert the user.
or maybe you want to limit the user to subscribe in only some given duration, say: user can only subscribe same service in each 1 day
You can update the record if the record already exist, for example:
Make a query to check if the record with particular user and service is exist:
SELECT * FROM table WHERE userid = userid AND serviceid=serviceid
If the query return any result, means its exist. then do update:
UPDATE table SET column1='value', column2='value2' ... WHERE userid = userid AND serviceid = serviceid
else, if no result returned, means the user haven't subscribe the service. then insert record:
INSERT INTO table(column1, column2, ...) values ('value1', 'value2', ...)
I think you could solve this problem with constraint. When user subscribes it inserts a row when it unsubscribes it deletes it. A row must be unique for same user and same service.
If you do not want to delete rows add ACTIVE column to this table and make constraint on USER + SERVICE + ACTIVE.
I do not fully understand your problem, but it seems you need to implement mutual exclusion somewhere. Have you tried with a SELECT ... FOR UPDATE?
http://www.techonthenet.com/oracle/cursors/for_update.php
I tried "MERGE" and subquery to solve this case.
By the way, this problem is only happened when subscribe. First, I get the status(subscribe or unsubscribe) from the last record of a user and the service. If the last status in table is 'subscribe', means this subscribed request might be the duplicated one.
MERGE INTO subscr_log M
USING
(SELECT status
FROM subscr_log
WHERE rid=
(SELECT MAX(rid)
FROM monthly_subscr_log
WHERE SCRID ='123456'
AND service_item='CHANNEL1'
)
) C
ON (C.status ='SUB' ) -- try to see the last record is subscribe or not
WHEN MATCHED THEN
UPDATE SET M.REASON='N/A' WHERE M.STATUS='XXXXXXX' --do impossible sql
WHEN NOT MATCHED THEN
INSERT VALUES (9999,8888,'x','x','x','x','x','x','x','x','x',sysdate,'x','x','x','x');
I'm asking myself if it is possible to SELECT with LAST_INSERT_ID() in WHERE Clause after an batch of INSERTs without getting corrupt data in the tables? I'm thinking of the scenario that multiple users doing the same stuff at the same time. I develop an JSF Application in which this scenario can be possible.
In hard Code my SELECT after INSERTs looks like this:
preparedstatement.addBatch(
"INSERT INTO table1(all the FIELDS)"
+ "VALUES(null, ...);"
);
preparedstatement.addBatch(
"INSERT INTO table2(all the FIELDS)"
+ "VALUES(null, LAST_INSERT_ID(), ...);"
);
preparedstatement = connect.prepareStatement(
"SELECT id FROM table3 WHERE id = LAST_INSERT_ID();"
);
preparedstatement.executeBatch();
resultSet = preparedstatement.executeQuery();
Get I problems with this implementation or is there an better way?
Best Regards
You should be fine, quoting MySQL's documentation:
The ID that was generated is maintained in the server on a
per-connection basis. This means that the value returned by the
function to a given client is the first AUTO_INCREMENT value generated
for most recent statement affecting an AUTO_INCREMENT column by that
client. This value cannot be affected by other clients, even if they
generate AUTO_INCREMENT values of their own. This behavior ensures
that each client can retrieve its own ID without concern for the
activity of other clients, and without the need for locks or
transactions.
MySQL Last_insert_id