How can I edit the latest row in the database. I only know it's the last one. I don't know its id.
I don't know which language you are working with, in PHP's mySQL functions you can use
mysql_insert_id()
there are similar function in every other mySQL client library I know of.
Also, there is a native mySQL function!
LAST_INSERT_ID() (with no argument)
returns the first automatically
generated value that was set for an
AUTO_INCREMENT column by the most
recently executed INSERT statement to
affect such a column. For example,
after inserting a row that generates
an AUTO_INCREMENT value, you can get
the value like this:
mysql> SELECT LAST_INSERT_ID();
-> 195
Of course, a primary key with AUTO_INCREMENT is required for these functions to work.
For a table with an auto_increment id field:
UPDATE tbl SET col1 = 'val1' WHERE id = MAX(id);
If it's a row that has been inserted in your script (the same script from which you want to update it) and there is an auto_increment column on your table, you can get that auto_increment value, using functions such as those, for PHP :
mysql_insert_id
mysqli_insert_id
PDO::lastInsertId
There should be an equivalent for probably any language you can possibly be using for your application.
If your are trying to do an update from another script than the one in which you did the insert, and still have an auto_increment column, the best way will probably be to update the row that has the biggest value for that column :
update your_table
set your_column = ...
where id = max(id)
Or, in two steps (not sure it'll work in one) :
select max(id) as id from your_table
update your_table set your_column = ... where id = [what you got with thr first query]
You can also use UPDATE table SET ... WHERE id=LAST_INSERT_ID() (supposing the last insert was on the table you want to query).
I would not use TWO steps to find the last insert ID simply because a new record could be added in the mean time.
Depending on your version, you should be able to call $handle->last_id(); or $handle->{mysql_insertid};
Chris
Related
I am working on TRANSACTION MySql and I have a problem:
BEGIN;
INSERT INTO a(name) VALUES("hello");
SELECT * FROM a WHERE name = "hello";
COMMIT/ROLLBACK;
So I can not find the value I have just added into table a. Please help me if there is any way to SELECT value that have just added.
Thanks a lot
If you want the auto increment ID value for the row you just inserted, you can get it with SELECT LAST_INSERT_ID().
If you want the whole row you just inserted, do this, assuming your table's autoincrement id is called id.
INSERT INTO a whatever;
SELECT * FROM a WHERE id = LAST_INSERT_ID();
You don't need an explicit transaction for this sequence of queries to work correctly. But, you can still use one for other purposes.
I know how LAST_INSERT_ID() works for auto incremented columns, but I cannot find a way to get the last id I inserted for a non auto incremented column.
Is there a way I can do that?
you can easily do that using the same LAST_INSERT_ID().
INSERT INTO thetable (id, value)
VALUES (LAST_INSERT_ID(126), 'some data');
SELECT LAST_INSERT_ID(); -- returns 126
I'm assuming you want the retrieve this last inserted id at some later point after inserting it, since if you need it right after inserting it you obviously would already know what the id is.
The only way you'll be able to get that is to have another column on the table that can indicate which row was last inserted, such as a timestamp or datetime column. If your ids are unique and increasing, you can just use that column. Then you just select 1 row ordered by that column in descending order.
For example
INSERT INTO my_table (id, timestamp) VALUES (123, NOW())
SELECT id FROM my_table ORDER BY timestamp DESC LIMIT 1
Edit: as per the comments below, you're much better off using an AUTO_INCREMENT column, though this column doesn't have to be the id column, you could add an auto-increment insert_order column of type Int and simply order by that.
I assume that you need the ID to find your just inserted row, rather to find the last inserted row. In a web application, you can never be sure that the last inserted row is the one you have just created.
You could use a GUID as id in this case. A GUID is usually stored as a string of length 36 or as a 16byte blob. The GUID can be created before inserting the row, and then can be stored while inserting the row.
Since the id is not auto incremented as you stated, you have to generate it anyway before inserting the row. The safest way to do this is to create a GUID which should be unique enough. Otherwise you would have to determine the last unused ID, what can be tricky and risky.
The easiest way I found to do this is to set a variable.
Unlike using LAST_INSERT_ID which only returns and INT this way you can use other unique identifiers.
SET #id = UUID();
INSERT INTO users (
id
)
VALUES (
#id
);
SELECT * FROM users WHERE id = #id;
No.
There is no inherent ordering of relations, no "last-inserted record". This is why the AUTO_INCREMENT field exists, after all.
You'd have to look in logs or cache the value yourself inside your application.
There's no way with mysql. But you can to do it programmatically. Without an auto-incrementing ID column there's no way for the database to know which records were inserted last.
One way to do is use such as a column containing timestamp or datetime values. and get id of latest value of tmestamp to get last inserted record
If you want to get a custom last_inserted ID, you must implement a procedure that will make the insert statment on your DB.
At the end, just print the ID and use the PHP (if PHP is your main script) sender to return the generated row.
EXAMPLE:
DROP PROCEDURE IF EXISTS insert_row;
DELIMITER $$
CREATE PROCEDURE insert_row(IN _row_id VARCHAR(255), IN _description VARCHAR(255))
BEGIN
SET #last_inserted_id = _row_id;
SET #sql = CONCAT("INSERT INTO test VALUES ('", _row_id, "','",_description,"')");
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SELECT #last_inserted_id AS LAST_INSERT_ID;
END;
$$
DELIMITER ;
#
#
#
#------- HOW TO USE IT ? ---------------
CALL insert_row('Test001','the first test line');
This worked for me in XAMPP
$qry = $con->query("INSERT INTO test_table(tbl_id, txt) VALUES(last_insert_id('15'), 'test value')");
print_r($con->insert_id);
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();
EDIT: This actually works fine, no idea why I thought otherwise.
I have a prices table which includes a column price_was which needs to contain the highest ever value for prices.
Is it possible to do a REPLACE query which would update this if required?
The following (which is simplified and built dynamically in PHP) doesn't seem to work.
REPLACE prices
SET price = 1.99,
price_was = IF(1.99 > price_was, 1.99, price_was)
id_product = 1
I'm thinking perhaps it's not possible, but would love to hear otherwise since I'm updating many records and need to be as efficient as possible.
The query you posted is indeed valid, try it for yourself. I would use an UPDATE though since you're only updating one field and the REPLACE can possible over-write other column data you want left alone.
Try INSERT ... ON DUPLICATE KEY UPDATE instead:
INSERT INTO prices (price, price_was, id_product)
VALUES (1.99, 1.99, 1)
ON DUPLICATE KEY UPDATE
price_was = IF(VALUES(price) > price_was, VALUES(price), price_was)
id_product = VALUES(id_product)
This will do either an INSERT or an UPDATE, while the REPLACE statement does either an INSERT or a DELETE followed by an INSERT. You are not able to reference old values in a REPLACE statement, probably because of the DELETE/INSERT semantics. From the docs:
Values for all columns are taken from
the values specified in the REPLACE
statement. Any missing columns are set
to their default values, just as
happens for INSERT. You cannot refer
to values from the current row and use
them in the new row. If you use an
assignment such as SET col_name =
col_name + 1, the reference to the
column name on the right hand side is
treated as DEFAULT(col_name), so the
assignment is equivalent to SET
col_name = DEFAULT(col_name) + 1.
Using MySQL 5.1.49, I'm trying to implement a tagging system
the problem I have is with a table with two columns: id(autoincrement), tag(unique varchar) (InnoDB)
When using query, INSERT IGNORE INTO tablename SET tag="whatever", the auto increment id value increases even if the insert was ignored.
Normally this wouldn't be a problem, but I expect a lot of possible attempts to insert duplicates for this particular table which means that my next value for id field of a new row will be jumping way too much.
For example I'll end up with a table with say 3 rows but bad id's
1 | test
8 | testtext
678 | testtextt
Also, if I don't do INSERT IGNORE and just do regular INSERT INTO and handle the error, the auto increment field still increases so the next true insert is still a wrong auto increment.
Is there a way to stop auto increment if there's an INSERT duplicate row attempt?
As I understand for MySQL 4.1, this value wouldn't increment, but last thing I want to do is end up either doing a lot of SELECT statements in advance to check if the tags exist, or worse yet, downgrade my MySQL version.
You could modify your INSERT to be something like this:
INSERT INTO tablename (tag)
SELECT $tag
FROM tablename
WHERE NOT EXISTS(
SELECT tag
FROM tablename
WHERE tag = $tag
)
LIMIT 1
Where $tag is the tag (properly quoted or as a placeholder of course) that you want to add if it isn't already there. This approach won't even trigger an INSERT (and the subsequent autoincrement wastage) if the tag is already there. You could probably come up with nicer SQL than that but the above should do the trick.
If your table is properly indexed then the extra SELECT for the existence check will be fast and the database is going to have to perform that check anyway.
This approach won't work for the first tag though. You could seed your tag table with a tag that you think will always end up being used or you could do a separate check for an empty table.
I just found this gem...
http://www.timrosenblatt.com/blog/2008/03/21/insert-where-not-exists/
INSERT INTO [table name] SELECT '[value1]', '[value2]' FROM DUAL
WHERE NOT EXISTS(
SELECT [column1] FROM [same table name]
WHERE [column1]='[value1]'
AND [column2]='[value2]' LIMIT 1
)
If affectedRows = 1 then it inserted; otherwise if affectedRows = 0 there was a duplicate.
The MySQL documentation for v 5.5 says:
"If you use INSERT IGNORE and the row is ignored, the AUTO_INCREMENT counter
is **not** incremented and LAST_INSERT_ID() returns 0,
which reflects that no row was inserted."
Ref: http://dev.mysql.com/doc/refman/5.5/en/information-functions.html#function_last-insert-id
Since version 5.1 InnoDB has configurable Auto-Increment Locking. See also http://dev.mysql.com/doc/refman/5.1/en/innodb-auto-increment-handling.html#innodb-auto-inc...
Workaround: use option innodb_autoinc_lock_mode=0 (traditional).
I found mu is too short's answer helpful, but limiting because it doesn't do inserts on an empty table. I found a simple modification did the trick:
INSERT INTO tablename (tag)
SELECT $tag
FROM (select 1) as a #this line is different from the other answer
WHERE NOT EXISTS(
SELECT tag
FROM tablename
WHERE tag = $tag
)
LIMIT 1
Replacing the table in the from clause with a "fake" table (select 1) as a allowed that part to return a record which allowed the insert to take place. I'm running mysql 5.5.37. Thanks mu for getting me most of the way there ....
The accepted answer was useful, however I ran into a problem while using it that basically if your table had no entries it would not work as the select was using the given table, so instead I came up with the following, which will insert even if the table is blank, it also only needs you to insert the table in 2 places and the inserting variables in 1 place, less to get wrong.
INSERT INTO database_name.table_name (a,b,c,d)
SELECT
i.*
FROM
(SELECT
$a AS a,
$b AS b,
$c AS c,
$d AS d
/*variables (properly escaped) to insert*/
) i
LEFT JOIN
database_name.table_name o ON i.a = o.a AND i.b = o.b /*condition to not insert for*/
WHERE
o.a IS NULL
LIMIT 1 /*Not needed as can only ever be one, just being sure*/
Hope you find it useful
You can always add ON DUPLICATE KEY UPDATE Read here (not exactly, but solves your problem it seems).
From the comments, by #ravi
Whether the increment occurs or not depends on the
innodb_autoinc_lock_mode setting. If set to a non-zero value, the
auto-inc counter will increment even if the ON DUPLICATE KEY fires
I had the same problem but didn't want to use innodb_autoinc_lock_mode = 0 since it felt like I was killing a fly with a howitzer.
To resolve this problem I ended up using a temporary table.
create temporary table mytable_temp like mytable;
Then I inserted the values with:
insert into mytable_temp values (null,'valA'),(null,'valB'),(null,'valC');
After that you simply do another insert but use "not in" to ignore duplicates.
insert into mytable (myRow) select mytable_temp.myRow from mytable_temp
where mytable_temp.myRow not in (select myRow from mytable);
I haven't tested this for performance, but it does the job and is easy to read. Granted this was only important because I was working with data that was constantly being updated so I couldn't ignore the gaps.
modified the answer from mu is too short, (simply remove one line)
as i am newbie and i cannot make comment below his answer. Just post it here
the query below works for the first tag
INSERT INTO tablename (tag)
SELECT $tag
WHERE NOT EXISTS(
SELECT tag
FROM tablename
WHERE tag = $tag
)
I just put an extra statement after the insert/update query:
ALTER TABLE table_name AUTO_INCREMENT = 1
And then he automatically picks up the highest prim key id plus 1.