MySQL current_insert_id()? (Not last_insert_id()) - mysql

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 :)

Related

Mysql SELECT value during transaction to use in same process [duplicate]

Let's say I am doing a MySQL INSERT into one of my tables and the table has the column item_id which is set to autoincrement and primary key.
How do I get the query to output the value of the newly generated primary key item_id in the same query?
Currently I am running a second query to retrieve the id but this hardly seems like good practice considering this might produce the wrong result...
If this is not possible then what is the best practice to ensure I retrieve the correct id?
You need to use the LAST_INSERT_ID() function: http://dev.mysql.com/doc/refman/5.0/en/information-functions.html#function_last-insert-id
Eg:
INSERT INTO table_name (col1, col2,...) VALUES ('val1', 'val2'...);
SELECT LAST_INSERT_ID();
This will get you back the PRIMARY KEY value of the last row that you inserted:
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.
So the value returned by LAST_INSERT_ID() is per user and is unaffected by other queries that might be running on the server from other users.
BEWARE !! of LAST_INSERT_ID() if trying to return this primary key value within PHP.
I know this thread is not tagged PHP, but for anybody who came across this answer looking to return a MySQL insert id from a PHP scripted insert using standard mysql_query calls - it wont work and is not obvious without capturing SQL errors.
The newer mysqli supports multiple queries - which LAST_INSERT_ID() actually is a second query from the original.
IMO a separate SELECT to identify the last primary key is safer than the optional mysql_insert_id() function returning the AUTO_INCREMENT ID generated from the previous INSERT operation.
From the LAST_INSERT_ID() documentation:
The ID that was generated is maintained in the server on a per-connection basis
That is if you have two separate requests to the script simultaneously they won't affect each others' LAST_INSERT_ID() (unless you're using a persistent connection perhaps).
You will receive these parameters on your query result:
"fieldCount": 0,
"affectedRows": 1,
"insertId": 66,
"serverStatus": 2,
"warningCount": 1,
"message": "",
"protocol41": true,
"changedRows": 0
The insertId is exactly what you need.
(NodeJS-mySql)
Here what you are looking for !!!
select LAST_INSERT_ID()
This is the best alternative of SCOPE_IDENTITY() function being used in SQL Server.
You also need to keep in mind that this will only work if Last_INSERT_ID() is fired following by your Insert query.
That is the query returns the id inserted in the schema. You can not get specific table's last inserted id.
For more details please go through the link The equivalent of SQLServer function SCOPE_IDENTITY() in mySQL?
If in python using pymysql, from the cursor you can use cursor.lastrowid.
It is a documented extension in PEP-249 DB API standard, and also works with other Python MySQL implementations.
You need to use the LAST_INSERT_ID() function with transaction:
START TRANSACTION;
INSERT INTO dog (name, created_by, updated_by) VALUES ('name', 'migration', 'migration');
SELECT LAST_INSERT_ID();
COMMIT;
http://dev.mysql.com/doc/refman/5.0/en/information-functions.html#function_last-insert-id
This function will be return last inserted primary key in table.
Simply use:
$last_id = mysqli_insert_id($conn);
If you need the value before insert a row:
CREATE FUNCTION `getAutoincrementalNextVal`(`TableName` VARCHAR(50))
RETURNS BIGINT
LANGUAGE SQL
NOT DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
COMMENT ''
BEGIN
DECLARE Value BIGINT;
SELECT
AUTO_INCREMENT INTO Value
FROM
information_schema.tables
WHERE
table_name = TableName AND
table_schema = DATABASE();
RETURN Value;
END
You can use this in a insert:
INSERT INTO
document (Code, Title, Body)
VALUES (
sha1( concat (convert ( now() , char), ' ', getAutoincrementalNextval ('document') ) ),
'Title',
'Body'
);
If you are using PHP: On a PDO object you can simple invoke the
lastInsertId method after your insert.
Otherwise with a LAST_INSERT_ID you can get the value like this: SELECT LAST_INSERT_ID();
i used return $this->db->insert_id(); for Codeigniter
Do this:
$idc = DB::table('tb_clients')->insertGetId([
'ide' => $ide,
'nome' => $nome,
'email' => $email
]);
on $idc you will get the last id
I just want to share my approach to this in PHP, some of you may found it not an efficient way but this is a 100 better than other available options.
generate a random key and insert it into the table creating a new row.
then you can use that key to retrieve the primary key.
use the update to add data and do other stuff.
doing this way helps to secure a row and have the correct primary key.
I really don't recommend this unless you don't have any other options.

LAST_INSERT_ID doesn't work in my case

$stmt2 = $db->prepare("INSERT INTO
usertabbrige(`tabId`,`uId`)
VALUES
((LAST_INSERT_ID()),$userId)");
anything wrong with this query? It's wrap within my first stmt, which will insert a value into uId (PK) in other table. usertabbrige table contain a field uId which is a FK.
Do not use LAST_INSERT_ID() in your query. You dont know which insert statement was last in current session. You can insert to one table, and if you use LAST_INSERT_ID() in another query, you dont actually know where LAST_INSERT_ID() came from.
As I can see you are using PDO. After you executed an insert query, save id:
$db->query("INSERT INTO ...");
$lastInsertedTabId = $db->lastInsertId;
Use it in your next prepared statement
$stmt2 = $db->prepare("INSERT INTO
usertabbrige(`tabId`,`uId`)
VALUES
($lastInsertedTabId ,$userId)");

Get the new record primary key ID from MySQL insert query?

Let's say I am doing a MySQL INSERT into one of my tables and the table has the column item_id which is set to autoincrement and primary key.
How do I get the query to output the value of the newly generated primary key item_id in the same query?
Currently I am running a second query to retrieve the id but this hardly seems like good practice considering this might produce the wrong result...
If this is not possible then what is the best practice to ensure I retrieve the correct id?
You need to use the LAST_INSERT_ID() function: http://dev.mysql.com/doc/refman/5.0/en/information-functions.html#function_last-insert-id
Eg:
INSERT INTO table_name (col1, col2,...) VALUES ('val1', 'val2'...);
SELECT LAST_INSERT_ID();
This will get you back the PRIMARY KEY value of the last row that you inserted:
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.
So the value returned by LAST_INSERT_ID() is per user and is unaffected by other queries that might be running on the server from other users.
BEWARE !! of LAST_INSERT_ID() if trying to return this primary key value within PHP.
I know this thread is not tagged PHP, but for anybody who came across this answer looking to return a MySQL insert id from a PHP scripted insert using standard mysql_query calls - it wont work and is not obvious without capturing SQL errors.
The newer mysqli supports multiple queries - which LAST_INSERT_ID() actually is a second query from the original.
IMO a separate SELECT to identify the last primary key is safer than the optional mysql_insert_id() function returning the AUTO_INCREMENT ID generated from the previous INSERT operation.
From the LAST_INSERT_ID() documentation:
The ID that was generated is maintained in the server on a per-connection basis
That is if you have two separate requests to the script simultaneously they won't affect each others' LAST_INSERT_ID() (unless you're using a persistent connection perhaps).
You will receive these parameters on your query result:
"fieldCount": 0,
"affectedRows": 1,
"insertId": 66,
"serverStatus": 2,
"warningCount": 1,
"message": "",
"protocol41": true,
"changedRows": 0
The insertId is exactly what you need.
(NodeJS-mySql)
Here what you are looking for !!!
select LAST_INSERT_ID()
This is the best alternative of SCOPE_IDENTITY() function being used in SQL Server.
You also need to keep in mind that this will only work if Last_INSERT_ID() is fired following by your Insert query.
That is the query returns the id inserted in the schema. You can not get specific table's last inserted id.
For more details please go through the link The equivalent of SQLServer function SCOPE_IDENTITY() in mySQL?
If in python using pymysql, from the cursor you can use cursor.lastrowid.
It is a documented extension in PEP-249 DB API standard, and also works with other Python MySQL implementations.
You need to use the LAST_INSERT_ID() function with transaction:
START TRANSACTION;
INSERT INTO dog (name, created_by, updated_by) VALUES ('name', 'migration', 'migration');
SELECT LAST_INSERT_ID();
COMMIT;
http://dev.mysql.com/doc/refman/5.0/en/information-functions.html#function_last-insert-id
This function will be return last inserted primary key in table.
Simply use:
$last_id = mysqli_insert_id($conn);
If you need the value before insert a row:
CREATE FUNCTION `getAutoincrementalNextVal`(`TableName` VARCHAR(50))
RETURNS BIGINT
LANGUAGE SQL
NOT DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
COMMENT ''
BEGIN
DECLARE Value BIGINT;
SELECT
AUTO_INCREMENT INTO Value
FROM
information_schema.tables
WHERE
table_name = TableName AND
table_schema = DATABASE();
RETURN Value;
END
You can use this in a insert:
INSERT INTO
document (Code, Title, Body)
VALUES (
sha1( concat (convert ( now() , char), ' ', getAutoincrementalNextval ('document') ) ),
'Title',
'Body'
);
If you are using PHP: On a PDO object you can simple invoke the
lastInsertId method after your insert.
Otherwise with a LAST_INSERT_ID you can get the value like this: SELECT LAST_INSERT_ID();
i used return $this->db->insert_id(); for Codeigniter
Do this:
$idc = DB::table('tb_clients')->insertGetId([
'ide' => $ide,
'nome' => $nome,
'email' => $email
]);
on $idc you will get the last id
I just want to share my approach to this in PHP, some of you may found it not an efficient way but this is a 100 better than other available options.
generate a random key and insert it into the table creating a new row.
then you can use that key to retrieve the primary key.
use the update to add data and do other stuff.
doing this way helps to secure a row and have the correct primary key.
I really don't recommend this unless you don't have any other options.

Is there a better way to find the ID of something in a table, even if it doesn't exist [mysql]

I very frequently use logic something like this when writing to normalised databases.
In pseudocode:
is the thing I want in the table?:
yes - get it's ID
else
no - insert it, then get it's ID
In PHP:
// is the useragent in the useragent table?
// if so, find the id, else, insert and find.
$useragentResult = $mysqli->query("SELECT id FROM useragent WHERE name = '".$useragent."' LIMIT 1");
if ($useragentResult->num_rows == 0) {
// It is not in there
$mysqli->query("INSERT INTO useragent (name) VALUES ('".$useragent."')");
$resultID_object = $mysqli->query("SELECT LAST_INSERT_ID() as id");
$row = $resultID_object->fetch_object();
$useragentID = $row->id;
} else {
// It is, so find it and set it
$useragentData = $useragentResult->fetch_object();
$useragentID = $useragentData->id;
}
This feels ugly (not just due to PHP!), and common enough that perhaps there is a better way.
What's the real way of doing this, or is this the best way?
Use INSERT ... ON DUPLICATE KEY UPDATE.
Since MySQL 5.5:
If a table contains an AUTO_INCREMENT column and INSERT ... ON DUPLICATE KEY UPDATE inserts or updates a row, the LAST_INSERT_ID() function returns the AUTO_INCREMENT value.
Or in earlier versions:
If a table contains an AUTO_INCREMENT column and INSERT ... ON DUPLICATE KEY UPDATE inserts a row, the LAST_INSERT_ID() function returns the AUTO_INCREMENT value. If the statement updates a row instead, LAST_INSERT_ID() is not meaningful. However, you can work around this by using LAST_INSERT_ID(expr). Suppose that id is the AUTO_INCREMENT column. To make LAST_INSERT_ID() meaningful for updates, insert rows as follows:
INSERT INTO table (a,b,c) VALUES (1,2,3)
ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(id), c=3;
It is ugly only insofar as you are using some basic PHP without taking full advantage of the language. For operations like this Object Oriented Programming comes in very handy. Rewriting your database access into classes would yield code more like this:
$userAgent = new UserAgent();
$userAgent->name = $useragent;
$results = $userAgent->find();
if (empty($results)) {
$userAgent->save();
}
$userAgentId = $userAgent->id;
In that example the find method of your UserAgent class does all the SQL work behind the scenes. If the find returns empty we call the save method which does an insert based on the properties that are populated and automatically populates the id property. So now after the if statement I know the id is populated either by a successful find() or by the save().

Access Auto-Increment Value During INSERT INTO Statement

I am currently using MySQL. I have a table that has an auto_increment 'id' field, and an 'imgname' field containing a string that is the file name of an image.
I need to generate the 'imgname' value using the auto_increment value that is create by an INSERT INTO statement. The problem is, I don't know this value until I can use mysql_insert_id, AFTER the insert query has run. I would like to know if it's possible to access this value DURING the insert query somehow and then use it to generate my string in the query statement.
Thanks in advance.
I would keep the id and imgname independent of each other and combine the two on SELECT when needed. If the need is frequent enough, create a view.
Have a look at LAST_INSERT_ID() function. If performance is not an issue, INSERT regularly, and then UPDATE using LAST_INSERT_ID(), like:
UPDATE table SET name = CONCAT(name, "-", LAST_INSERT_ID()) WHERE id = LAST_INSERT_ID();