pdo get the last inserted id or the last updated row - php

I have a PDO statement that insert or update a row depending on a UNIQUE column (if the column exist then update) . I wonder if there is a solution for both to get the id of the INSERTED or UPDATED that I could use in the same query. So ...
considering this answer ... how could it be together?
SET #update_id := 0;
UPDATE some_table SET column_name = 'value', id = (SELECT #update_id := id)
WHERE some_other_column = 'blah' LIMIT 1;
SELECT #update_id;
plus
lastInsertId();
meaning something like (I'm not sure if there would be a sintax for this so I just set what i have in mind:
IF "INSERT" then SELECT lastInsertId()
else if "UPDATE" then select ID of the last row updated;

Related

How do I loop last insert id

I have these set of queries, its working fine except that I'm only able to get one value from LAST_INSERT_ID() in my UPDATE query;
$query .= "INSERT into itemorders
(itemID,colourID,itemName,itemSize,itemPrice,quantity,orderID) SELECT
itemID,colourID,itemName,itemSize,itemPrice,quantity,
LAST_INSERT_ID() FROM mycart WHERE email='".$email."'; ";
$query .= "UPDATE CatalogueItemsSize p
INNER JOIN itemorders i ON p.size = i.itemSize AND p.colourID =
i.colourID SET p.quantity = p.quantity - i.quantity WHERE i.id =
LAST_INSERT_ID();";
I understand that it can only retrieve the last single inserted row, how do I loop this so that I am able to catch all the values inserted in the first query?
Currently it is only subtracting quantity one row from the CatalogueItemsSize Table.
The Last insert ID ONLY returns the LAST inserted record's ID.
If you need to get the last insert ID for each record inserted, you will need to run your SELECT statement, get the results, then run an INSERT statement for each record in your SELECT and then run your update with the last_insert_id()
Also, in your INSERT statement, the last_insert_id() there will likely either cause an error or at the very least have unintended consequences.

mysql insert record not immediately available, select count(*) doesn't see it right away

In my php code, I have a Mysql query:
SELECT COUNT(*)
to see if the record already exists, then if it doesn't exist I do an:
INSERT INTO <etc>
But if someone hits reload with a second or so, the SELECT COUNT(*) doesn't see the inserted record.
$ssql="SELECT COUNT(*) as counts FROM `points` WHERE `username` LIKE '".$lusername."' AND description LIKE '".$desc."' AND `info` LIKE '".$key."' AND `date` LIKE '".$today."'";
$result = mysql_query($ssql);
$row=mysql_fetch_array($result);
if ($row['counts']==0) // no points for this design before
{
$isql="INSERT INTO `points` (`datetime`,`username`,`ip`,`description`,`points`,`info`, `date`,`uri`) ";
$isql=$isql."VALUES ('".date("Y-m-d H:i:s")."','".$lusername."',";
$isql=$isql."'".$_SERVER['REMOTE_ADDR']."','".$desc."','".$points."',";
$isql=$isql."'".$key."','".$today."','".$_SERVER['REQUEST_URI']."')";
$iresult = mysql_query($isql);
return(true);
}
else
return(false);
I was using MyISAM database type
Instead of running two seperate queries just use REPLACE INTO.
From the documentation:
REPLACE works exactly like INSERT, except that if an old row in the table has the same value as a new row for a PRIMARY KEY or a UNIQUE index, the old row is deleted before the new row is inserted.
For example if your key field is id then:
REPLACE INTO my_table SET id = 4 AND other_field = 'foobar'
will insert if there is no record with id 4, or if there is then it will replace the other_field value with foobar.

Get both insert_id and updated row id in insert_update query

I have a query like this:
SET #uids = '';
INSERT INTO tbl1 (name,used,is_active)
VALUES (1,0,0),(2,0,0),(24,0,0)
ON DUPLICATE KEY UPDATE
id = LAST_INSERT_ID(id)
, used = (SELECT #uids := concat_ws(',', LAST_INSERT_ID(), #uids))
, used = used+1
, is_active = CASE WHEN used > 3 THEN 1 ELSE 0 END;
SELECT #uids;
See here to figure out the way of getting updated row id.
I get updated row ids' in #uids if it updates any rows but if a row is inserted, I can't get the id of that. So how to get both inserted row id and updated row id?
Or how to execute (SELECT #uids := concat_ws(',', LAST_INSERT_ID(), #uids)) in insert before ON DUPLICATE KEY... ?
Time's short and we are long
You can't do it, because there is no way to fill #uids while inserting which needs a select clause and you are not allowed to use a select clause within an insert statement unless your query can be transformed into an INSERT ... SELECT.
Long answer
As long as you don't try to insert mixed values that may result in both updating and inserting (which probably you do) there is a nasty but safe way you can go with:
SET #uids := '';
INSERT INTO `tbl1` (name, used, is_active)
VALUES (1,0,0),(2,0,0),(24,0,0)
ON DUPLICATE KEY UPDATE
is_active = CASE WHEN used > 3 THEN 1 ELSE 0 END,
id = LAST_INSERT_ID(id),
used = used + 1,
id = (SELECT #uids := concat_ws(',', LAST_INSERT_ID(), #uids));
SELECT #uids, LAST_INSERT_ID() as f, MAX(id) as l from `tbl1`;
Being not so tricky, you have two values at the end:
LAST_INSERT_ID() as f is the first inserted row ID
MAX(id) as l which is last inserted row ID
So with that two boundaries you surly have all inserted rows IDs. Saying that it has drawbacks and that is you always have a LAST_INSERT_ID() value even if rows only were affected by update statement. However as you tagged your question with php there was a chance to get benefit from mysqli_affected_rows while doing a multi_query but I couldn't produce expected return values from mysqli_affected_rows as is documented by MySQL:
For INSERT ... ON DUPLICATE KEY UPDATE statements, the affected-rows
value per row is 1 if the row is inserted as a new row, 2 if an
existing row is updated, and 0 if an existing row is set to its
current values.
You can try it yourself and see if it works. If you get an expected return value then you can understand if your query has done some updates or inserts and read results based on that
As my short answer, there is no correct way to do it within the same query context but may be doing it programatically is neater? (though I don't bet on its performance)
$values = [[1, 0, 0], [2, 0, 0], [24, 0, 0]];
$insertIDs = [];
$updateIDs = [];
foreach ($values as $v) {
$insert = $mysqli->prepare("INSERT INTO `tbl1` (name, used, is_active) VALUES (?, ?, ?)");
$insert->bind_param('ddd', $v[0], $v[1], $v[2]);
$insert->execute();
if ($insert->affected_rows == -1) {
$update = $mysqli->prepare("UPDATE `tbl1` SET id = LAST_INSERT_ID(id), used = used + 1, is_active = CASE WHEN used > 3 THEN 1 ELSE 0 END WHERE name = ?"); // considering `name` as a unique column
$update->bind_param('d', $v[0]);
$update->execute();
if ($update->affected_rows == 1) {
$updateIDs[] = $update->insert_id;
}
} else {
$insertIDs[] = $insert->insert_id;
}
}
var_dump($updateIDs);
var_dump($insertIDs);
Example output:
array(1) {
[0]=>
int(140)
}
array(1) {
[0]=>
int(337)
}
One another workaround could be using MySQL triggers. By creating an AFTER INSERT trigger on table tbl1, you are able to store IDs for later use:
CREATE TRIGGER trigger_tbl1
AFTER INSERT
ON `tbl1` FOR EACH ROW
BEGIN
UPDATE `some_table` SET last_insert_ids = concat_ws(',', LAST_INSERT_ID(), last_insert_ids) WHERE id = 1;
END;

Use inserted id for another column value

I have an identity column (id) that auto-increments.
id|name|image_path
I want to know if there is some way using mysql, to use the newly inserted id in the image_path.
For example if a new row is inserted and got the id 2 I want the image_path to be "/images/2.png".
Or do I have to use the traditional way, by inserting and then fetching this ID then updating the entry?
My opinion is that it is impossible to do with one query. You won't know new autoincrement value until row will be inserted. Still you can write 1 query to achieve what you want (actually 2 queries would be executed):
insert into `t`(`id`, `name`, `image_path`)
values(
(SELECT `auto_increment` FROM INFORMATION_SCHEMA.TABLES
WHERE `table_name` = 't'),
'1234',
concat(
'/images/',
(SELECT `auto_increment` FROM INFORMATION_SCHEMA.TABLES
WHERE `table_name` = 't'),
'.png'
)
)
Anyway much safer would be:
START TRANSACTION;
set #c = (select ifnull(max(`id`),0) + 1 from `t`);
insert into `t`(`id`, `name`, `image_path`) values (#c,'123',concat('/images/',#c,'.png'));
COMMIT;
Yes, it is possible with oracle. We have dynamic sql feature.
have tried the below.
Created a sequence and then created a procedure which takes id as input and creates an insert statement dynamically which will fulfill your requirement.
create sequence seq1 start with 1;
create table image1(id1 number,image varchar2(50));
create or replace procedure image1_insert(id1 in number)
as
sql_stmt varchar2(50);
image_path varchar2(50);
begin
sql_stmt:='insert into image1 values(:1,:2)';
image_path:='/image/'||id1||'.png';
execute immediate sql_stmt using id1,image_path;
end;
begin
image1_insert(seq1.nextval);
end;
id image
4 /image/4.png
5 /image/5.png
select *from image1;

Count rows in one table within a IF statement

Is it possible to check if num rows in a table is 0 then perform an insert, all in ONE sql statement?
Here's my query that I tried but it says I have a syntax error:
$query =
"IF (SELECT COUNT(ID) FROM votes WHERE userid = $userid AND itemid = $itemid AND itemtype=1) = 0
INSERT INTO votes (itemtype, itemid, userid) VALUES (1, $itemid, $userid)
SELECT 1 AS result
ELSE
SELECT 0 AS result
END IF";
I know the SELECT COUNT bit works successfully on its own.
NO IDEA if this is the best way of solving this, but it will work. Basically, it simply causes an error if the condition is false, and so it prevents insert:
-- make itemtype not nullable then simply insert
INSERT INTO votes SELECT
CASE
WHEN
(SELECT COUNT(ID)
FROM votes
WHERE userid = $userid AND itemid = $itemid AND itemtype=1) = 0 THEN 1
ELSE NULL
END CASE,
$itemid, $userid;
I don't have access to MySQL to test this right now, but would this work?
INSERT INTO votes (itemtype, itemid, userid)
(SELECT 1,$itemid, $userid
WHERE NOT EXISTS (
SELECT *
FROM votes
WHERE itemtype=1
AND itemid=$itemid
AND userid=$userid))

Categories