I am trying to retrieve the auto increment value of last inserted data in mySQL. Here is my code:
public int getAutoIncrementProductID() {
ResultSet rs = null;
DBController db = new DBController();
db.getConnection();
int autoIncKeyFromFunc = -1;
rs = db.readRequest("SELECT LAST_INSERT_ID()");
try {
if (rs.next()) {
autoIncKeyFromFunc = rs.getInt(1);
System.out.println("AUTO ID IS " + autoIncKeyFromFunc);
rs.close();
}
} catch (Exception e) {
e.printStackTrace();
}
db.terminate();
return autoIncKeyFromFunc;
}
However, these codes keep returning me 0 value although the auto increment column in database is keep increasing. It just wont get the auto increment value of last inserted data. Anybody could help?
You should use LAST_INSERT_ID() after you insert something.
For LAST_INSERT_ID(), the most recently generated ID is maintained in
the server on a per-connection basis. It is not changed by another
client. It is not even changed if you update another AUTO_INCREMENT
column with a nonmagic value (that is, a value that is not NULL and
not 0).
Source
You may also try
SELECT max(id) FROM tableName
But it will not suppose deleted rows.
How about this?
SELECT your_id FROM your_table ORDER BY your_id DESC LIMIT 1
I think since you are using Jdbc there is another way to get generated key is to use API connection. createStatement (Statement.RETURN_GENERATED_KEYS); Look at this thread PreparedStatement with Statement.RETURN_GENERATED_KEYS
I use this:
SELECT auto_increment + 1 AS NEXT_ID
FROM `information_schema`.`tables`
WHERE table_name = "table_name"
AND table_schema = "database_name"
Be Careful when using mysql_insert_id() specially if you have multiple connections to the Database. Because It doesn't get the value of the query you've inserted. it gets the latest id of the table. It may be a row another query has inserted. Only use this function if you access Database in one connection.
If you want to get the id of the query you've inserted, try to select the row with an unique value you've inserted with that query. Ex : finding the user id of a user with his email address.
SELECT id from users where emailaddress='me#johndoe.com' LIMIT 1
More details here :
https://www.php.net/manual/en/function.mysql-insert-id.php
How about this?
SHOW TABLE STATUS FROM Database_Name LIKE 'TableName' ;
Related
Normally I can insert a row into a MySQL table and get the last_insert_id back. Now, though, I want to bulk insert many rows into the table and get back an array of IDs. Does anyone know how I can do this?
There are some similar questions, but they are not exactly the same. I don't want to insert the new ID to any temporary table; I just want to get back the array of IDs.
Can I retrieve the lastInsertId from a bulk insert?
Mysql mulitple row insert-select statement with last_insert_id()
Old thread but just looked into this, so here goes: if you are using InnoDB on a recent version of MySQL, you can get the list of IDs using LAST_INSERT_ID() and ROW_COUNT().
InnoDB guarantees sequential numbers for AUTO INCREMENT when doing bulk inserts, provided innodb_autoinc_lock_mode is set to 0 (traditional) or 1 (consecutive).
Consequently you can get the first ID from LAST_INSERT_ID() and the last by adding ROW_COUNT()-1.
The only way I can think it could be done is if you store a unique identifier for each set of rows inserted (guid)
then select the row ids.
e.g:
INSERT INTO t1
(SELECT col1,col2,col3,'3aee88e2-a981-1027-a396-84f02afe7c70' FROM a_very_large_table);
COMMIT;
SELECT id FROM t1
WHERE guid='3aee88e2-a981-1027-a396-84f02afe7c70';
You could also generate the guid in the database by using uuid()
Lets assume we have a table called temptable with two cols uid, col1 where uid is an auto increment field. Doing something like below will return all the inserted id's in the resultset. You can loop through the resultset and get your id's. I realize that this is an old post and this solution might not work for every case. But for others it might and that's why I'm replying to it.
# lock the table
lock tables temptable write;
#bulk insert the rows;
insert into temptable(col1) values(1),(2),(3),(4);
#get the value of first inserted row. when bulk inserting last_insert_id() #should give the value of first inserted row from bulk op.
set #first_id = last_insert_id();
#now select the auto increment field whose value is greater than equal to #the first row. Remember since you have write lock on that table other #sessions can't write to it. This resultset should have all the inserted #id's
select uid from temptable where uid >=#first_id;
#now that you are done don't forget to unlock the table.
unlock tables;
It's worth noting that #Dag Sondre Hansen's answer can also be implemented in case you have innodb_autoinc_lock_mode set to 2 by simply locking the table before insert.
LOCK TABLE my_table WRITE;
INSERT INTO my_table (col_a, col_b, col_c) VALUES (1,2,3), (4,5,6), (7,8,9);
SET #row_count = ROW_COUNT();
SET #last_insert_id = LAST_INSERT_ID();
UNLOCK TABLES;
SELECT id FROM my_table WHERE id >= #last_insert_id AND id <= #last_insert_id + (#row_count - 1);
Here's a fiddle demonstrating: https://www.db-fiddle.com/f/ahXAhosYkkRmwqR9Y4mAsr/0
I wouldn't be sure that auto increment value will increase item by 1. and there will be huge problems if your DB will have Master // Master replication and to resolve auto_increment duplicate exclusion. AI will be +2 instead of +1, also if there will be one more master it will come to +3. so relay on thing like AUTO_INCREMENT is going up for 1 is killing your project.
I see only some good options to do that.
this SQL snippet will have no problems with multiple masters and give good results until you will need only inserted records. on multiple requests without transactions can catch other inserts records.
START TRANSACTION;
SELECT max(id) into #maxLastId FROM `main_table`;
INSERT INTO `main_table` (`value`) VALUES ('first'), ('second') ON DUPLICATE KEY UPDATE `value` = VALUES(`value`);
SELECT `id` FROM `main_table` WHERE id > #maxLastId OR #maxLastId IS NULL;
COMMIT;
(if you will need also updated records by DUPLICATE KEY UPDATE) you will need to refactor database a bit and SQL will look like next, (safe for transactions and no transactions inside one connection.)
#START TRANSACTION
INSERT INTO bulk_inserts VALUES (null);
SET #blukTransactionId = LAST_INSERT_ID();
SELECT #blukTransactionId, LAST_INSERT_ID();
INSERT INTO `main_table` (`value`, `transaction_id`) VALUES ('first', #blukTransactionId), ('second', #blukTransactionId) ON DUPLICATE KEY UPDATE `value` = VALUES(`value`), `transaction_id` = VALUES(`transaction_id`);
SELECT #blukTransactionId, LAST_INSERT_ID();
SELECT id FROM `main_table` WHERE `transaction_id` = #blukTransactionId;
#COMMIT
both cases are safe to transnational. first will show you only inserted records and second will give you all records even updated.
also those options will work even with INSERT IGNORE ...
This thread is old but all these solutions did not help me so I came up with my own.
First, count how many rows you want to insert
let's say we need to add 5 rows:
LOCK TABLE tbl WRITE;
SELECT `AUTO_INCREMENT` FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'my_db' AND TABLE_NAME = 'tbl'
then use the auto_increment just selected to do next query:
ALTER TABLE tbl AUTO_INCREMENT = {AUTO_INCREMENT}+5;
UNLOCK TABLES;
Finally do your inserts
Use the reserved autoincrement range to insert with id.
Warning: this solution requires elevated access level to the tables. But usually bulk inserts are run by crons and importer scripts and what not that may use special access anyway. You would not use this for just a few inserts.
This may leave unused id's if you use ON DUPLICATE KEY UPDATE.
I think you will have to either handle the transaction id in your application, or the item id in your application in order to do this flawlessly.
One way to do this which could work, assuming that all your inserts succeed (!), is the following :
You can then get the inserted id's with a loop for the number of affected rows, starting with lastid (which is the first inserted id of the bulk insert).
And thus, i checked it works perfectly .. just be careful that HeidiSQL for example will not return the correct value for ROW_COUNT(), probably because it's a crappy GUI doing random shit we don't ask it - however it's perfectly correct from either command line or PHP mysqli -
START TRANSACTION;
BEGIN;
INSERT into test (b) VALUES ('1'),('2'),('3');
SELECT LAST_INSERT_ID() AS lastid,ROW_COUNT() AS rowcount;
COMMIT;
In PHP it looks like this (local_sqle is a straight call to mysqli_query, local_sqlec is a call to mysqli_query + convert resultset to PHP array) :
local_sqle("START TRANSACTION;
BEGIN;
INSERT into test (b) VALUES ('1'),('2'),('3');");
$r=local_sqlec("SELECT LAST_INSERT_ID() AS lastid,ROW_COUNT() AS rowcount;");
local_sqle("
COMMIT;");
$i=0;
echo "last id =".($r[0]['lastid'])."<br>";
echo "Row count =".($r[0]['rowcount'])."<br>";
while($i<$r[0]['rowcount']){
echo "inserted id =".($r[0]['lastid']+$i)."<br>";
$i++;
}
The reason the queries are separated is because I wouldn't otherwise get my result using my own functions, if you do this with standard functions, you can put it back in one statement and then retrieve the result you need (it should be result number 2 - assuming you use an extension which handles more than one result set / query).
For anyone using java with JDBC, it is possible. I am getting ids back with batch-insert doing it like this:
PreparedStatement insertBatch = null;
Connection connection = ....;
for (Event event : events) {
if (insertBatch == null){
insertBatch = connection.prepareStatement("insert into `event` (game, `type`, actor, target, arg1, arg2, arg3, created) " +
"values (?, ?, ?, ?, ?, ?, ?, ?)", Statement.RETURN_GENERATED_KEYS);
}
insertBatch.setObject(1, event.game);
insertBatch.setString(2, event.type);
insertBatch.setObject(3, event.actor);
insertBatch.setObject(4, event.target);
insertBatch.setString(5, event.arg1);
insertBatch.setObject(6, event.arg2);
insertBatch.setObject(7, event.arg3);
insertBatch.setTimestamp(8, new Timestamp(event.created.getTime()));
insertBatch.addBatch();
}
}
if (insertBatch != null){
insertBatch.executeBatch();
ResultSet generatedKeys = insertBatch.getGeneratedKeys();
for (Event event : events) {
if ( generatedKeys == null || ! generatedKeys.next()){
logger.warn("Unable to retrieve all generated keys");
}
event.id = generatedKeys.getLong(1);
}
logger.debug("events inserted");
}
Source: "Using MySQL I can do it with JDBC this way:" - Plap - https://groups.google.com/g/jdbi/c/ZDqnfhK758g?pli=1
I have to actually add this to my JDBC url: rewriteBatchedStatements=true. Or else the actual inserts show up in the mysql "general query log" as separate rows. With 7000 rows inserted, I got 2m11s for regular inserts, 46s without rewrite.. on and 1.1s with rewrite.. on. Also, it does not make other people's inserts block (I tested that). When I inserted 200k rows, it grouped them into about 36k per line ie insert into abc(..) values(..),(..),(..)....
I am actually using JDBCTemplate so the way to access the PreparedStatement is:
ArrayList<Long> generatedIds = (ArrayList<Long>) jdbcTemplate.execute(
new PreparedStatementCreator() {
#Override
public PreparedStatement createPreparedStatement(Connection connection) throws SQLException {
return connection.prepareStatement(insertSql, Statement.RETURN_GENERATED_KEYS);
}
},
new PreparedStatementCallback<Object>() {
#Override
public Object doInPreparedStatement(PreparedStatement ps) throws SQLException, DataAccessException {
// see above answer for setting the row data
...
ps.executeBatch();
ResultSet resultSet = ps.getGeneratedKeys();
ArrayList<Long> ids = new ArrayList<>();
while (resultSet.next()) {
ids.add(resultSet.getLong(1));
}
return ids;
}
}
);
$query = "INSERT INTO TABLE (ID,NAME,EMAIL) VALUES (NULL,VALUE1, VALUE2)";
$idArray = array();
foreach($array as $key) {
mysql_query($query);
array_push($idArray, mysql_insert_id());
}
print_r($idArray);
This question already has answers here:
How to get the next auto-increment id in mysql
(21 answers)
Closed 9 years ago.
I am using MySQL.
I want to retrieve the next value that the AUTO_INCREMENT column will take without entering a new record.
create table ABC(id int(10) NOT NULL AUTO_INCREMENT,name char(10));
In oracle I would have used sequencename.nextval(); But what to I use in MySQL?
Here is why I did not use
select max(id) from ABC;
Suppose I have an entry with id=2. Now column id will take the next value as 3.
Before I create a record with id=3, If I delete the record with id=2.
The answer for query I mentioned will be 2. But I want the actual value 3, which the auto_increment column will anyway take.
Query table status like this:
SHOW TABLE STATUS WHERE `Name` = 'table_name'
Now in result you will get a column named Auto_increment. This is the value You were asking for.
In JAVA:
conn = DriverManager.getConnection(connectionUrl, connectionUser, connectionPassword);
stmt = conn.createStatement();
rs = stmt.executeQuery("SHOW TABLE STATUS WHERE `Name` = 'table_name'");
rs.next();
String nextid = rs.getString("Auto_increment");
Full example here: http://www.avajava.com/tutorials/lessons/how-do-i-use-jdbc-to-query-a-mysql-database.html
If I understand correctly,you could use the number of rows as indicator:
SELECT TABLE_ROWS+1
FROM information_schema.tables
WHERE table_name='tableName'
AND table_schema = DATABASE();
There is no way to guarantee what value you are going to get before inserting the row. This is mostly because you will have to lock the entire table to guarantee no other thread will do an insert with "your" next value.
You can reserve a value by starting a transaction, inserting a row, getting the value and then doing a rollback. Then you can safely use that value.
It will be much simpler to just insert the row, so maybe I'm not understanding the purpose of what you are doing.
In Mysql I am inserting a row with Insert command in a table of mysql , now I want the Id of last row Inserted , I am using
SELECT LAST_INSERT_ID() ;
But it gives me 0 as output every time .
Please help me in this.
LAST_INSERT_ID() only returns values that have been auto-generated by the MySQL server for an AUTO_INCREMENT column; when you insert a specific value, no auto-generation takes place and no value will be returned by LAST_INSERT_ID().
You could assign a value to LAST_INSERT_ID yourself:
INSERT INTO table (uuid) VALUES (LAST_INSERT_ID(12345));
LAST_INSERT_ID(value) assigns value to be returned by subsequent calls to LAST_INSERT_ID(), and returns that same value. Unfortunately, this only works for integer values, and will not be useful with UUIDs.
Why would you want to select something that is not autogenerated by insert, but passed to it? The reason is that you are using UUID() in the insert statement. I'd suggest you first to select the UUID, and then pass it to the insert
SELECT #id := UUID();
INSERT INTO tablename(id, value) VALUES(#id, somevalue)
you are assigning autoincrement an uuid this is what you are doing wrong
autoincrement field will be inserted automatically
other than that you will be getting 0 result in LAST_INSERT_ID()
First you have to use one auto incremented line.
if you are using php then use this method :
$foo = mysql_insert_id();
take a look http://php.net/manual/en/function.mysql-insert-id.php
in c# i use like this:
connection.Open();
cmd = new MySql.Data.MySqlClient.MySqlCommand();
cmd.Connection = connection;
cmd.CommandText = "INSERT INTO o_test(game_id, user_id, date) values(?game_id, ?uid, ?date)";
cmd.Prepare();
cmd.Parameters.AddWithValue("?game_id", null);
cmd.Parameters.AddWithValue("?uid", words[1]);
cmd.Parameters.AddWithValue("?date", words[2]);
cmd.ExecuteNonQuery();
int game_id;
cmd.Parameters.Add(new MySqlParameter("newId", cmd.LastInsertedId));
game_id = Convert.ToInt32(cmd.Parameters["#newId"].Value);
If you want to select all columns from the last inserted id, you can go that way:
SELECT * FROM table WHERE id = (SELECT MAX(id) FROM table)
On my db-server i am inserting data in a table having a auto increment field say 'id'. Now i want to use the value of this last inserted 'id' in subsequent steps. I can use this:-
select * from table_name order by id desc limit 1;
But the problem here is, it is a server and many more insertions could be happening and there could be a case where i try to retrieve the data with the query i mentioned and get a different id ie. between my insert and select there could be some other insert and i wont get the value i inserted. Any way in which this could be addressed.?
Thanks in advance.
Use this
mysql_insert_id(&mysql);
as its basic structure are
mysql_insert_id ([ resource $link_identifier = NULL ] )
Retrieves the ID generated for an AUTO_INCREMENT column by the previous query (usually INSERT).
or in mysql use
SELECT LAST_INSERT_ID();
here is the ref links
http://dev.mysql.com/doc/refman/5.0/en/getting-unique-id.html
http://php.net/manual/en/function.mysql-insert-id.php
try this
SELECT LAST_INSERT_ID(colid) From tablename;
heres the Link
call LAST_INSERT_ID() function immediately after insertion and save id somewhere.
Use this mysql_insert_id()
It returns the AUTO_INCREMENT ID generated from the previous INSERT operation.
This function returns 0 if the previous operation does not generate an AUTO_INCREMENT ID, or FALSE on MySQL connection failure.
you can get the id if you call LAST_INSERT_ID() function immediately after insertion and then you can use it.
For any last inserted record will be get through mysql_insert_id()
If your table contain any AUTO_INCREMENT column it will return that Value.
mysql_query("INSERT INTO test(emsg,etime) values ('inserted',now())");
printf("Last inserted record has id %d\n", mysql_insert_id());
$last_id=mysql_insert_id();
echo $last_id;
?>
I am inserting a row with a char column for a hash based on (among other things) the row's auto id.
I know I can insert it, fetch the insert_id, calculate the hash, and update it.
Does anyone know of a way to do this in a single query? You would need the rows insert_id at the time of insert. Is that completely impossible, or is there something like current_insert_id()...
Thanks!
No, there's no function in MySQL that gives you the current_insert_id().
The only way to get a generated ID value from an AUTO_INCREMENT field in MySQL is to do the INSERT and then call last_insert_id(). So your plan of doing a separate UPDATE to calculate the hash is probably what you'll have to do.
I can think of two other alternatives:
Generate the unique value yourself before the INSERT with some other mechanism besides the AUTO_INCREMENT. For example, see the UUID() function.
SET #id = SELECT UUID();
INSERT INTO MyTable (id, hash) VALUES (#id, hash(#id...));
Don't include the ID in your hash calculation.
There's no way that I know of to do it in MySQL in one query, but you could do something like this in your server-side scripting language of choice:
<?php
$query = mysql_query("SHOW TABLE STATUS LIKE 'MyTable'");
$row = mysql_fetch_assoc($query);
$next_id = $row['Auto_increment'];
?>
...which gives you the id to incorporate in your SQL.
EDIT: I also found this answer which may be helpful.
You can query the next-to-be-used value from the information_schema.TABLES table, the AUTO_INCREMENT column there. (You might be setting yourself up for a race condition?)
When I do inserts I do something like this:
INSERT INTO table (col1,col2) VALUES (data1,data2);SELECT LAST_INSERT_ID()
and just run the query like I was fetching data. In VB.NET the syntax is (assuming you have the MySql.Data.MySqlClient .dll):
Dim sql As String = "[sql string above]"
Dim dr As MySqlDataReader = YourRetrieveDataFunction(sql)
dr.Read()
yourObjectInstance.ID = dr(0)
dr.Close
It's technically two queries, but only one hit on the database :)