This question already has answers here:
PHP: Calling MySQL Stored Procedure with Both INPUT AND OUTPUT Parameters (NOT "INOUT")
(2 answers)
Closed 3 years ago.
To call a Stored procedure with an IN parameter is easy like
CREATE PROCEDURE `catalog_delete_product`(IN `inProductId` INT) BEGIN DELETE FROM product_attribute WHERE product_id = inProductId; DELETE FROM product_category WHERE product_id = inProductId; DELETE FROM shopping_cart WHERE product_id = inProductId; DELETE FROM product WHERE product_id = inProductId; END
You can see that it is as easy as that. But how do we call an OUT parameter in MySQL Stored parameter and use it in PHP?
As an example to illustrate it, I will a real world practical example(inserting data into an order table and returning the lastInsertId).
CREATE PROCEDURE `shopping_cart_create_order`(IN `inCartId` INT(11), OUT `newOrderId` INT(11)) BEGIN
DECLARE newOrder int;
-- Insert a new record into orders and obtain the new order ID
INSERT INTO orders (created_on) VALUES (NOW());
-- Obtain the new Order ID
SELECT LAST_INSERT_ID() INTO newOrder;
SET newOrder = newOrderId;
END
At PHP level// Probably at the Model/Entity level First, we need to execute the
shopping_cart_create_order()
stored procedure. Which might probably be in a function.
Second, to get the last order id, we need to query it from the variable
#oid
. It is important that we must call the method
closeCursor()
of the PDOStatement object in order to execute the next SQL statement.
function query($pdo, $sql, $parameters = []){
$query = $pdo->prepare($sql);
$query->execute($parameters);
return $query;
}
function create_order($pdo, $cart_id){
// Binding the parameters
$parameters = [':cart_id' => $cart_id];
// calling stored procedure command
$sql = 'CALL shopping_cart_create_order(:cart_id)';
// prepare for execution of the stored procedure, pass value to the command
and execute the Stored Procedure
$query = query($pdo, $sql, $parameters);
// Then close Cursor. It is important for you to close it.
$query->closeCursor();
// execute the second query to get last insert id
$row = $pdo->query("SELECT #oid AS oid")->fetch();
return $row;
}
Related
This question already has answers here:
How to UPSERT (MERGE, INSERT ... ON DUPLICATE UPDATE) in PostgreSQL?
(7 answers)
Postgres on conflict do update on composite primary keys
(2 answers)
Closed 6 months ago.
I have a problem with my SQL statement written in PHP.
I am using store() function to both INSERT or UPDATE object in the database following it's rule that it can be done:
The INSERT OR UPDATE command is an extension of the INSERT command, with these differences:
If the row being inserted does not exist, INSERT OR UPDATE performs an
INSERT operation. If the row being inserted already exists, INSERT OR
UPDATE performs an UPDATE operation, updating the row with the
specified column values.
I wrote type declaration for the Content ID like : public ?$contentId = null; so I can use the same methods for both actions.
public function store(Content $content, int $teamId)
{
$rsm = new ResultSetMapping($this->entityServiceRepository);
$stmt = $this->entityServiceRepository->getConnection()->prepare(
'UPDATE content
SET
name = :name,
url = :url,
WHERE id = :contentId
AND team_id = :teamId
',
$rsm
);
$stmt->bindValue("contentId", $content->getId(), PDO::PARAM_INT);
$stmt->bindValue("teamId", $content, PDO::PARAM_INT);
$stmt->bindValue("name", $content->getName(), PDO::PARAM_STR);
$stmt->bindValue("url", $content->getUrl(), PDO::PARAM_STR);
$stmt->executeQuery();
However from some reason data does not exist in the database. All bindValue() return true ant other sql queries seems to work well. How can I debug this query? Or can someone tell is there a problem with sql query I wrote.
Thanks.
I am in a need to call a stored procedure in a loop by using PDO. This procedure return multiple rows (not by OUT param). The problem I am facing is that sequential call adds all the results from previous calls to the new result. Say, if a single call with specific param returns 20 rows, second call will return 40 rows, third one - 60, etc. Param can be different from call to call while the results will still stack. The code I am using:
public function call($proc, $params) {
$this->query = 'CALL '.$proc.'(?);';
$this->statement = $this->pdo->prepare($this->query);
$this->statement->execute($params);
$data = $this->statement->fetchAll(PDO::FETCH_ASSOC);
$this->statement->nextRowset();
$this->statement->closeCursor();
return $data;
}
From my understanding, I have probably failed with freeing the resources and fetching entire data, however no data is available after fetchAll. Why am I getting results from previous calls?
Edit: here is a similar code of sproc used in application (_type is IN param):
BEGIN
DECLARE _start_entry INT UNSIGNED;
DECLARE _next_entry INT UNSIGNED;
CREATE TEMPORARY TABLE IF NOT EXISTS `tableT` AS (SELECT * FROM `table` LIMIT 0);
SELECT `entry` FROM `table` WHERE `type` = _type LIMIT 1 INTO _start_entry;
read_loop: LOOP
INSERT INTO `tableT` (SELECT * FROM `table` WHERE entry = _start_entry);
SELECT `next_entry` FROM `table` WHERE entry = _start_entry INTO _next_entry;
SELECT _next_entry INTO _start_entry;
IF _next_entry = 0 THEN
LEAVE read_loop;
END IF;
END LOOP read_loop;
SELECT * FROM `tableT`;
END
Turns out the problem was that multiple calls were perfomed within the same session. This leads temporary table tableT to exist among all the calls and contain results from previous calls. Easy fix:
[...]
SELECT * FROM `tableT`;
DROP TABLE `tableT`; <-- this
END
Calling SELECT Statements with parameters is great and makes life coding so tidy. My problem comes to when I want to update data in the database using an UPDATE statement.
I have the Stored Proc with the UPDATE statement included, similar to this below
CREATE DEFINER = 'myuser'#'%'
PROCEDURE sp_upd_planning (
IN prop_id int(11),
IN planned_date varchar(15),
IN time_slot int(11),
IN by_who int(11),
IN cost decimal(15,2),
IN complete_date varchar(15),
IN lastupd_user varchar(100))
BEGIN
UPDATE planning
SET
Status = CASE
WHEN CompleteDate IS NOT NULL THEN 4
WHEN PlannedDate IS NULL THEN 2
WHEN PlannedDate IS NULL AND CompleteDate IS NULL THEN 3
END
,PlannedDate = planned_date
,BookingDate = NOW()
,TimeSlot = time_slot
,ByWho = by_who
,Cost = epc_cost
,Complete = CASE WHEN CompleteDate IS NOT NULL THEN 1 ELSE 0 END
,CompleteDate = complete_date
,LastUpdateDate = NOW()
,LastUpdateUser = lastupd_user
WHERE PropID = prop_id;
END
The statement works as should when I run the CALL sp_upd_planning(paramters here); within the database.
I'm using as a submit from a form, I've posted the relevant fields into variables and in my connection I call the Stored Proc again and as before in the database I use the variables to match the parameters needed like this (yes I know it's using mysql_ but I wanted to test quickly so I used this)
mysql_query("CALL sp_upd_planning('$planned', '$timeslot', '$bywho', '$cost', '$completed', '$inputby', $propid)") or die(mysql_error());
When the code executes all looks good and no errors and the main form submits as should with the jquery I set up, but when I check the database nothing is updated.
Why would this be?
It sounds like you aren't executing your statement. In PHP you still have to execute the statement after creation. Also if I remember correctly it is more secure to bind your parameters instead of pass them in the string. Try something like this:
$conn = new mysqli("mysql:host=$host;dbname=$dbname", $username, $password);
// execute the stored procedure
$sql = "CALL sp_upd_planning(:planned, :timeslot, :bywho, :cost, :completed, :inputby, :propid)";
$stmt = $conn->prepare($sql);
$stmt->bindParam('datatypes', $planned, $timeslot, $bywho, $cost, $completed, $inputby, $propid);
$stmt->execute();
Basically by the term datatypes lets assume the planned is a string, timeslot is a date/time, bywho is a string, cost is an int, completed is an int, inputby is a string, and propid is an int then it would say 'sdsiisi'
I never used stored procedures, but I faced a reality when I need to move my query to server. Please assist.
This is my function that I created via PHP:
function getResults($userid) {
$query = "select * from myTable where iduser= ?";
$stmt = $this->openDb()->prepare($query);
$stmt->bindValue(1, $userid, PDO::PARAM_INT);
$stmt->execute();
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
return $rows;
}
I never used stored procedures and not sure how to approach:
How do I add this as stored procedure to MySQL, so I could submit
one integer variable to it
How do I `prepare' the integer variable that I will submit to stored procedure
How do I retrieve the result set from stored procedure back to php
function.
If you could assist, I will review your solution and will be able to continue on my own.
I checked google and I see that to create a stored procedure I need to start like this:
CREATE PROCEDURE `getResults` (IN userid INT)
BEGIN
END
MYSQL:
DELIMITER $$
DROP PROCEDURE IF EXISTS getResults$$
CREATE PROCEDURE getResults(IN I_USERID INT(10))
BEGIN
SELECT * FROM `myTable` WHERE iduser = I_USERID;
END$$
DELIMITER ;
PHP:
$sql = "CALL getResults(?)";
$stmt = $this->openDb()->prepare($sql);
$stmt->execute(array($userid));
while ($row = $stmt->fetchObject()) {
//use fields like this: $row->fieldname1, $row->fieldname2...
}
$stmt->closeCursor();
On a side note, I would recommend naming explicitely your fields instead of using the * selector in your query.
Hope it helps,
S.
I've been trying to find an answer to this question, but haven't found any definitive "yes" or "no" in all my research.
I'm running a simple MySQL query like this:
UPDATE item SET `score`=`score`+1 WHERE `id`=1
Is there a way for that query to return the updated value, instead of the number of rows affected? Just as a reference, I'm doing this in PHP, so the actual code looks like:
$sql = "UPDATE item SET `score`=`score`+1 WHERE `id`=1";
$new_value = mysql_query($sql);
//Unfortunately this does not return the new value
I know I could do a second query and just SELECT the value, but I'm trying to cut down on queries as much as possible. Is there a way?
You can do it with a stored procedure that updates, and then selects the new value into an output parameter.
The following returns one column new_score with the new value.
DELIMITER $$ -- Change DELIMITER in order to use ; withn the procedure
CREATE PROCEDURE increment_score
(
IN id_in INT
)
BEGIN
UPDATE item SET score = score + 1 WHERE id = id_in;
SELECT score AS new_score FROM item WHERE id = id_in;
END
$$ -- Finish CREATE PROCEDURE statement
DELIMITER ; -- Reset DELIMITER to standard ;
In PHP:
$result = mysql_query("CALL increment_score($id)");
$row = mysql_fetch_array($result);
echo $row['new_score'];
No, there's nothing like postgresql's UPDATE ... RETURNING output_expression in MySQL (yet?).
If you don't want to run another Query SELECT then here is another way to do it. I have modified Mr. Berkowski code for reference:
DELIMITER $$
CREATE PROCEDURE increment_score
(
IN id_in INT
)
BEGIN
set #newScore := null;
UPDATE item SET score = IF((#newScore := score+1) <> NULL IS NULL, #newScore, NULL) WHERE id = id_in;
SELECT #newScore;
END
DELIMITER ;
No you cant. You could make a function or stored procedure that could do the insert and return the updated value but that would still require you to execute two queries from within the function or stored procedure.
You can create a trigger, and you will know everything about the modifications.