MySQL INSERT with OUTPUT like MSSQL - mysql

I am pretty sure MySQL does not have the INSERT INTO table OUTPUT [column value] that MSSQL does - http://msdn.microsoft.com/en-us/library/ms177564.aspx (or http://blogs.msdn.com/b/sqltips/archive/2005/06/13/output-clause.aspx)
What's an easy way to replicate this? (I am moving a MSSQL app to MySQL. The 'OUTPUT' is a unique identifier and a int currently, so maybe I could just SELECT MAX (int) and add one, and generate a UID prior to insert?)
Thanks

If this value is an auto-increment field, you can run SELECT LAST_INSERT_ID(); after running the insert, and you'll get the last value inserted into this field.
See: http://dev.mysql.com/doc/refman/5.0/en/information-functions.html#function_last-insert-id

Related

mysql stored procedure, select max value and insert the value and assign to variable

I am porting a MSSQL stored procedure to MYSQL and i have a stored procedure that does this.
get the last value in a table by select Max.
add the new value to the table (along with other record
get the last value and store it in a variable for other processing
So far what i have the following
DECLARE lastSeq INT Default 0;
SELECT max(seq) INTO lastSeq from mytable;
Set newSeq = lastSeq + 1;
insert into mytable (seq, value1, value2, value3) values (newSeq, 1, 2, 3);
Unfortunately this is NOT thread safe, say if I select max(seq) and then a new record was added by other thread running a different query, by the time i reach insert, the value is already wrong.
In MSSQL I did this by locking the table during query of max(seq).
BUT
MYSQL does not allow locking of tables in stored procedure, so I cannot directly port the approach.
Havent had the luck to find solution while searching, maybe i am not putting the right keywords in search.
How can I do this in MYSQL thread safe inside stored procedure?
Update: I cannot use auto_increment for this column as this column is not unique and we allow duplicate, maybe my sample is wrong since i used "sequence" which should be auto increment, but in my real code, i use it for a different column that allows duplication.
example;
record id userid name seq status
1 1 adam 1 A
2 1 adam 2 C
3 2 Bob 1 C
In the above record, we have 2 records for Adam but only one valid set to "C" as current and "A" as archived or old value.
so my table has 2 valid record,
This is a bit long for a comment.
So change the data type to be auto_increment. There is no need to do re-implement this logic in a trigger, when the database basically does it for you.
If you are concerned about gaps, then just use row_number() over (order by seq) when you query the table.

MySQL LAST_INSERT_ID() question potential

If i have insert query for example:
INSERT INTO user(username) VALUES('admin');
And then get the id of the inserted record with
LAST_INSERT_ID();
Looks find but what happens if between the insert and LAST_INSERT_ID() another insert is executed.
How MySQL knows to return the correct id (for the first or second insert) since no parameter is passed to LAST_INSERT_ID();
Is it save to use this function?
Thanks
I'm supposing that you mean what happen if i'm connected to the MySQL server and executing an INSERT but others are also doing insert, like updating a table on a website while client are currently using it.
If you go take a look at the documentation https://dev.mysql.com/doc/refman/8.0/en/information-functions.html there is a point that answers your questions:
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.
This should be the same in MariaDB.
As discussed in the comment, you are wondering if you can use this in a php PDO environment. If you mean to use this directly from the database, it's a no, you won't be able to have the last inserted ID because you won't have the same client connection as PDO. If you want to use it directly from PDO please use the specific PDO function: http://php.net/manual/fr/pdo.lastinsertid.php , this should allow to do what you want.
If you insert multiple rows into a table using a single INSERT query, the LAST_INSERT_ID function returns the last insert id of the first row.
i.e
If your table id has 3 as column value and you will insert 4 rows in a single query then LAST_INSERT_ID will give you 4 instead of 7
If you insert 4 rows in 4 different insert query then LAST_INSERT_ID will give you 7
last_insert_id( ) Or mysqli_insert_id( ) will always return the id of last or most recent query. And also be noted that id field must have AUTO_INCREMENT enabled.
It doesn't give you the freedom to choose any specific table. Or you can't have id which is generated from your previous query.
So, from this point it serves a very small purpose. Only the last id, it doesn't matter which table.
To get last id from any specific table this query would be helpful : "SELECT id FROM table_name ORDER BY id DESC LIMIT 1"

How to get inserted IDs of multiple rows on one INSERT?

I want to insert multiple rows into a table, using a single INSERT statement. This is no problem, since SQL offers the option to provide multiple rows as parameter for a single INSERT statement. Now, those rows contain an ID field that is incremented automatically, i.e. its value is set by the database, not by my code.
As a result, I would like to get the ID values of the inserted rows. My basic question is: How do I do that for MariaDB / MySQL?
As it turns out, this is pretty simple, e.g. in PostgreSQL, as PostgreSQL has the RETURNING clause for INSERT which returns the desired values for one or even for multiple rows. This is exactly what I want and it works.
Unfortunately, neither MariaDB nor MySQL have PostgreSQL's RETURNING clause, so I need to fallback to something such as LAST_INSERT_ID(), but this only returns the ID of the single last inserted row, even if multiple rows were inserted using a single INSERT. How do I get all the ID values?
My code currently looks like this:
INSERT INTO mytable
(foo, bar)
VALUES
('fooA', 'barA'),
('fooB', 'barB');
SELECT LAST_INSERT_ID() AS id;
How can I solve this issue in a way that works even with concurrent writes?
(And no, it's not an option to change to a UUID field, or something like this; the auto-increment field is given, and can not be changed.)
MySQL & MariaDB have the LAST_INSERT_ID() function, and it returns the id generated by the most recent INSERT statement in your current session.
But when your INSERT statement inserts multiple rows, LAST_INSERT_ID() returns the first id in the set generated.
In such a batch of multiple rows, you can rely on the subsequent id's being consecutive. The MySQL JDBC driver depends on this, for example.
If the rows you insert include a mix of NULL and non-NULL values for the id column, you have a risk of messing up this assumption. The JDBC driver returns the wrong values for the set of generated id's.
As stated in the comments, you can capture the inserted IDs (SQL Server):
use tempdb
create table test (
id int identity(1,1) primary key,
t varchar(10) null
)
create table ids (
i int not null
)
insert test(t)
output inserted.id into ids
values (null), (null), (null)
select *
from test
select *
from ids

MySQL select after insert

Lets asume a table like:
ID = INT, AutoIncrement
VAR = VARCHAR, 65
FOO = VARCHAR, 65
I want to insert something new, and get the Auto-Generated ID, for further use.
My current solution is:
1.INSERT into table (VAR,FOO) VALUES ('test','anothertest')
2.SELECT * FROM table ORDER BY ID LIMIT 1
To get the last insert, but the problem is, what happends if the website lags, and there is a time gap between the queries?
example:
12:00AM 0.000s -> "INSERT into table (VAR,FOO) VALUES ('test','anothertest')
12:00AM 0.500s -> "INSERT into table (VAR,FOO) VALUES ('xyz', '!!!!!)`
12:00AM 0.800s -> "SELECT * FROM table ORDER BY ID LIMIT 1
the Query in 3 would not return the ID from 1, it would return the ID from 2
My Question no is, is there an absolute secure way to get a Value from a inserted Query?
like a confirmation "test, anothertest has successfully inserted into table, ID is 20"
the ID should be available as variable in php, just for information
Since you mention PHP there is usually a specific function to get that. If you are using the mysqli drivers then see mysqli_insert_id
Edit: According to the docs linked above The value of the AUTO_INCREMENT field that was updated by the previous query. Returns zero if there was no previous query on the connection or if the query did not update an AUTO_INCREMENT value. Since it is talking about queries on the connection then I would interpret that as meaning that queries on other connection (i.e. queries from other requests) won't affect the value returned. As long as you call it dirctly after the insert (before you do anythign else) then it should work.
Caveat: I am simply interpreting the docs here. I haven't actually tested for other calls myself. Wouldn't be that difficult though - simply have a script which does an insert, a sleep then fetches the ID, giving you time to do another insert during the sleep.
In php I use mysql_insert_id();
In later MySql insert/update I use LAST_INSERT_ID()
It's absolutely the same.
Try using, Scope_Identity(). This returns the last autogenerated id.
This link has more info: http://msdn.microsoft.com/en-us/library/ms190315.aspx

How to get the id of an inserted row ON insert?

I would like to create a unique hash of an AUTO-INCREMENT field while inserting that row. Something like:
INSERT INTO `table` (`hash`,`salt`) VALUES (MD5(CONCAT(`id`,`salt`)),'1234789687');
Is it possible to use the AUTO-INCREMENTED id of the row WHILE I'm inserting? Or do I have to wait until it's inserted to grab it via PHP or something?
The short answer is no- it is not possible. If your db has low transaction volume, then concurrency may not be an issue to use something similar to select max() (susceptible to interference) : Can you access the auto increment value in MySQL within one statement?
I would follow the insert in php with an update
update `table`
set `hash` = MD5(CONCAT(`id`,`salt`))
where `id` = LAST_INSERT_ID();
I don't know for sure, but really doubt that this is possible. I see why you would want to thought...It's not so elegant to insert the row, then immediately update it.
I would consider if you really need to store the hash in the DB or if you can calculate it during the select:
SELECT MD5(CONCAT(id,salt)) FROM table WHERE ...