Say a table T with a PRIMARY KEY id, I set it to AUTO INCREMENT.
I need to get the newly INSERTED id value for other operation, however, since it's the only PRIMARY KEY and AUTO INCREMENT, I don't how to do it.
Another SELECT with all other values in WHERE is valid in theory, but it's too slow.
Any better ideas?
Should you be checking LAST_INSERT_ID() like
select LAST_INSERT_ID();
Does this not work?
select max(id) from T;
This will produce the last id without functions
SELECT id FROM t ORDER BY id DESC LIMIT 1
By the way .. You should get the id after your insert statement from any MySQL api
It obviously depends on what database engine you use.
If , like I suppose, We are speaking about MSSQL, a good practise is to return last id generated in the current transaction (or session). You could see this post for more info.
Anyway, you could calculate the max id, but whitout warranties if someone instert new row in the while.
Related
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"
If I delete the max IDs (for example 9, 10,11) from the table, the sql will not begin from the max existing ID ! it begins with 12!
is it possible to let the sql add new id according to existing max id?
how to get the max primary key autoincrement in the table (the deleted one too)?
This code finds the existing only and not the deleted ids:
select max(id) from table1
If I delete the max IDs (for example 9, 10,11) from the table, the sql will not begin from the max existing ID ! it begins with 12 !
That is correct. There is nothing surprising or exclamation-worthy about this. That's how RDBMSes work.
1- is it possible to let the sql add new id according to existing max id ?
Not easily at all. As a matter of fact, it is so difficult, and any attempt to do it would be so tied to the particular RDBMS that you are using, (that is, so not portable,) that you are advised to not even try. That's because RDBMSes are built for highly concurrent use, so they have to be able to prevent the possibility of different clients inserting inconsistent primary key values.
2- how to get the max primary key autoincrement in the table
There really is no such thing as a "max primary key autoincrement in the table", because it may be changing at a very fast rate as someone is inserting rows into the table, so by the time your select max(id) from table1 would return a value to you, the actual max value in the database may already be different.
After inserting new data into a table, I need to select some of the new data straight after, so I can use it for inserting into another table.
The only way I can think of doing this is using the 'datetime' field I have in my row, but how would I retrieve the latest date/time inserted.
INSERT statement with NOW() value for datetime
society_select = SELECT socID, creator, datetime FROM societies.society WHERE datetime='[..datetime is the newest...]';
Hope that makes sense. Thank you
There are a number of ways to do this.
Why not make use of a trigger for this?
When a trigger creates a record you can get the id's of the records inserted. You can then do a select and insert new values into the relevant table.
MYSQL has loads of resources on using triggers.
http://dev.mysql.com/doc/refman/5.0/en/triggers.html
Or you can get the number of rows affected then use this to get the required result set in a select statement.
Get the last inserted ID?
If you are inserting one row into the database at a time then you would be able to get the last inserted id from MYSQL. This will be the Primary Key value of the record you last inserted into the database.
You would basically do something like this in mysql:
SET #inserted_id = LAST_INSERT_ID();
Or in PHP you can use the function:
mysql_insert_id(&mysql);
http://dev.mysql.com/doc/refman/5.0/en/getting-unique-id.html
Sort the results by their datetime in descending order, and select the first of them.
society_select = SELECT socID, creator, datetime FROM societies.society ORDER BY datetime DESC LIMIT 1;
you can use this with an auto increment filed. after inserting data you can retrieve the list inserted id from the table. and use that id to get the latest record.
A trigger as suggested is an option. If you don't want to use that for some kind of reason you can:
Add an integer primary key with auto_increment as ID and sort it DESC (e.g. INT(11))
Sort descending on a timestamp column (ofcourse with an index on it)
Use a trigger after inserting the data. This is for sure the cleaner way.
Another option is to use a method like mysql_insert_id. Assumed that you use PHP. There are of course equivalent methods in other languages as well.
Sorting is not an option(if not wrapped smart in transaction) - If you have multiple writes and reads on the table this might end up pretty ugly.
All rows in MySQL tables are being inserted like this:
1
2
3
Is there any way how to insert new row at a top of table so that table looks like this?
3
2
1
Yes, yes, I know "order by" but let me explain the problem. I have a dating website and users can search profiles by sex, age, city, etc. There are more than 20 search criteria and it's not possible to create indexes for each possible combination. So, if I use "order by", the search usually ends with "using temporary, using filesort" and this causes a very high server load. If I remove "order by" oldest profiles are shown as first and users have to go to the last page to see the new profiles. That's very bad because first pages of search results always look the same and users have a feeling that there are no new profiles. That's why I asked this question. If it's not possible to insert last row at top of table, can you suggest anything else?
The order in which the results are returned when there's no ORDER BY clause depends on the RDBM. In the case of MySQL, or at least most engines, if you don't explicitly specify the order it will be ascending, from oldest to new entries. Where the row is located "physically" doesn't matter. I'm not sure if all mysql engines work that way though. I.e., in PostgreSQL the "default" order shows the most recently updated rows first. This might be the way some of the MySQL engines work too.
Anyway, the point is - if you want the results ordered - always specify sort order, don't just depend on something default that seems to work. In you case you want something trivial - you want the users in descending order, so just use:
SELECT * FROM users ORDER BY id DESC
I think you just need to make sure that if you always need to show the latest data first, all of your indexes need to specify the date/time field first, and all of your queries order by that field first.
If ORDER BY is slowing everything down then you need to optimise your queries or your database structure, i would say.
Maybe if you add the id 'by hand', and give it a negative value, but i (and probably nobody) would recommend you to do that:
Regular insert, e.g.
insert into t values (...);
Update with set, e.g.
update t set id = -id where id = last_insert_id();
Normally you specify a auto_incrementing primary key.
However, you can just specify the primary key like so:
CREATE TABLE table1 (
id signed integer primary key default 1, <<-- no auto_increment, but has a default value
other fields .....
Now add a BEFORE INSERT trigger that changes the primary key.
DELIMITER $$
CREATE TRIGGER ai_table1_each BEFORE INSERT ON table1 FOR EACH ROW
BEGIN
DECLARE new_id INTEGER;
SELECT COALESCE(MIN(id), 0) -1 INTO new_id FROM table1;
SET NEW.id = new_id;
END $$
DELIMITER ;
Now your id will start at -1 and run down from there.
The insert trigger will make sure no concurrency problems occur.
I know that a lot of time has passed since the above question was asked. But I have something to add to the comments:
I'm using MySQL version: 5.7.18-0ubuntu0.16.04.1
When no ORDER BY clause is used with SELECT it is noticeable that records are displayed, regardless of the order in which they are added, in the table's Prime Key sequence.
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 ...