I am creating a MySQL Event but it relates with table record id,
so when that record is deleted at that time this MySQL Event should be deleted.
It worked with my code but what if record is directly deleted from phpMyAdmin?
Trying this scenario, the Event is not deleted and record does not exist. So an error occured.
$this->db->insert("invoice", $data);
$last = $this->db->insert_id();
if ($last)
$str = $this->db->last_query();
$this->db->query("SET GLOBAL event_scheduler = 'ON'");
$this->db->query("CREATE EVENT rec" . $last . " ON SCHEDULE
EVERY 1 MONTH STARTS DATE_SUB(NOW(),INTERVAL '0:01' HOUR_MINUTE)
ON COMPLETION PRESERVE ENABLE DO $str");
How can I overcome this problem? I Heard that i can use a trigger but How?
Make a trigger like this:
SET #ename:='rec';
SET #sql_text = concat('CREATE TRIGGER delete_invoice_event AFTER DELETE on TABLE FOR EACH ROW BEGIN DROP EVENT IF EXISTS ', #ename ,'old.id END');
PREPARE stmt FROM #sql_text;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
You have to use PREPARE statement, because your event name is dynamic, based on the deleted record id that would be accessible by old.id
Related
Let Suppose i have Following code which updates two different table
if(isset($_POST['submit'])){
$updateq = $conn->query("UPDATE `tbl1` SET `field1`= '$field1'");
$updater = $conn->query("UPDATE `tbl2` SET field2 ='$field2'");
//Here I want to check if first update query
//is affected any row or not
if(mysqli_affected_rows($conn) > 0){
....
}
}
So is it possible to check whether first query is updated any row or not ?
IN mysql
ROW_COUNT() returns the number of rows changed, deleted, or inserted by the last statement if it was an UPDATE, DELETE, or
INSERT. For other statements, the value may not be meaningful.
so,
UPDATE `tbl1` SET `field1`= '$field1'
SET #countRow = ROW_COUNT();
if (#countRow>0) then
UPDATE `tbl2` SET field2 ='$field2'
end if;
you have to integrate this in php as it is purely mysql syntax
I want to run an update like such in PHP
// pseudocode
UPDATE invoice SET due_date=? WHERE invoice_id=? AND creater_id=?;
IF AFFECTED_ROWS == 1 THEN
UPDATE invoice_item SET price=? WHERE invoice_id=?
For added security, I appended creater_id to ensure that the code only updates if the logged in user is the invoice creator, otherwise, the system will not update.
I originally intended to check this condition using AFFECTED_ROWS. But eventually after much frustration, I realise AFFECTED_ROWS return 0 if all the new values are the same as the old values. This means that even if I have different values for the invoice_item, they will not be updated.
Other than doing a SELECT before the UPDATE, is there SQL query or PHP functions that will tell me if the UPDATE matched any row, so that I can proceeed to UPDATE invoice_item accordingly?
You can use ROW_COUNT() and if you read that it explains that when connecting to the DB you can specify the CLIENT_FOUND_ROWS flag which will give the number of rows found for the update, regardless of if they have the same value of what you're updating with.
Hope this helps.
I've taken this from my code so things like $link need to be in place- but it shows what you are interested in
function update() {
$q = "UPDATE table SET field1=? WHERE field2 = $value";
/* create a prepared statement */
$stmt = mysqli_stmt_init($link);
if (mysqli_stmt_prepare($stmt, $q)) {
mysqli_stmt_bind_param($stmt, "s", $field1);
mysqli_stmt_execute($stmt);
if(mysqli_stmt_errno($stmt)){
echo("Sql Error: ".$q. ' Sql error #: '.mysqli_stmt_errno($stmt). ' - ' . mysqli_stmt_error($stmt);
return false;
}
else{
$numrows = mysqli_stmt_affected_rows($stmt);
if (mysqli_stmt_errno($stmt) == 0 || mysqli_stmt_errno($stmt) ==''){
// numrows = -1 is flag no error and no rows affected
$numrows = ($numrows ==0?-1:$numrows);
}
else{
echo("Sql Error: ".$q. ' Sql error #: '.mysqli_stmt_errno($stmt). ' - ' . mysqli_stmt_error($stmt);
return false;
}
/* close statement */
mysqli_stmt_close($stmt);
return $numrows;
}
}
}
As per documentation on ROW_COUNT():
ROW_COUNT() returns the number of rows changed, deleted, or inserted by the last statement if it was an UPDATE, DELETE, or INSERT. For other statements, the value may not be meaningful.
Your query:
Other than doing a SELECT before the UPDATE, is there SQL query or PHP functions that will tell me if the UPDATE matched any row
You can also use ROW_COUNT() within an UPDATE or any other DDL or DML statement.
Example: Using your pseudocode:
// pseudocode
UPDATE invoice SET due_date=? WHERE invoice_id=? AND creater_id=?;
IF ( ROW_COUNT() >= 1 ) THEN
UPDATE invoice_item SET price=? WHERE invoice_id=?
END IF;
Or else, you can try like:
UPDATE invoice SET due_date=? WHERE invoice_id=? AND creater_id=?;
UPDATE invoice_item SET price=
(case when ( row_count() >= 1 ) then ? else price end)
WHERE invoice_id=?;
Before setting the parameter value check again for the row_count() value to decide whether to set values for 1 or more parameters.
You can take this back to 1 query and not worry about affected rows:
UPDATE
invoice
left join invoice_item on invoice_item.invoice_id = invoice.invoice_id
SET
invoice.due_date = ?, -- the WHERE will only let this happen if it will be changed
invoice_item.price = ? -- the WHERE will only let this happen if it will be changed
WHERE
invoice.invoice_id = ?
and invoice.creater_id = ?
and invoice.due_date != ? -- here compare the new due_date to the one already in the db
hi i am using mysql trigger to update a table on another table's insertion
this trigger works fine
CREATE TRIGGER `update_pupil_subject` AFTER INSERT ON `pupil_marks`
FOR EACH ROW
BEGIN
UPDATE pupil_subjects SET NumberOfStudens = NumberOfStudens + 1 WHERE NEW.SubjectID = SubjectID;
END$$
but this gives an error
CREATE TRIGGER `update_pupil_subject` AFTER INSERT ON `pupil_marks`
FOR EACH ROW
BEGIN
UPDATE pupil_subjects SET NumberOfStudens = NumberOfStudens + 1 , AverageMarks = (SELECT AVG(Marks) FROM pupil_marks WHERE NEW.StudentID = StudentID ) WHERE NEW.SubjectID = SubjectID;
END$$
how to write this correctly , please help . thanks in advance .
Apparently there were problems when sub-queries were used:
Can you try splitting the SQL statement:
DELIMITER $$
CREATE TRIGGER `update_pupil_subject`
AFTER INSERT
ON `pupil_marks`
FOR EACH ROW
BEGIN
DECLARE avg_marks float;
SELECT AVG(Marks)
INTO avg_marks
FROM pupil_marks
WHERE NEW.SubjectID = SubjectID;
UPDATE pupil_subjects
SET NumberOfStudens = NumberOfStudens + 1, AverageMarks = avg_marks
WHERE NEW.SubjectID = SubjectID;
END
$$
Edit: Use
SHOW TRIGGERS WHERE `table` = 'pupil_marks';
to get all triggers defined on pupil_marks. You can't have multiple triggers on an event as all actions can be covered in single trigger.
NOTE: I think AVG(Marks) is for a given subject, so modified trigger definition accordingly.
declare a variable inside the trigger and assign it with the subquery
declare avg_mark integer default 0;
set avg_mark := (SELECT AVG(Marks) FROM pupil_marks WHERE NEW.StudentID = StudentID);
then use the variable "avg_mark" in your update statement...
it may work...
if not then check the delimiter just below phpmyadmin sql box . It should be "$$"
In a regular single query statement to MySQL, I can use mysql_affected_rows()==1 to determine whether or not something was updated. Now suppose I am trying to perform a transaction of the following:
USE myDB;
START TRANSACTION;
UPDATE members SET member_active=0 WHERE member_id = 53;
UPDATE member_subscriptions SET subscription_active=0 WHERE member_id = 53;
COMMIT;
ROLLBACK;
Since I have those two update statements, should I could on a successful transaction being equivalent to mysql_affected_rows()==2 ?
OR, is there a better way I should be checking for success?
You should hold the value of mysql_affected_rows in variables. And total updation will be some of those variables.
If you have track of both transactions and can have even better judgment which transaction is not performed and what would be the reaction.
USE myDB;
START TRANSACTION;
UPDATE members SET member_active=0 WHERE member_id = 53;
$count1= mysql_affected_rows();
UPDATE member_subscriptions SET subscription_active=0 WHERE member_id = 53;
$count2= mysql_affected_rows();
COMMIT;
ROLLBACK;
$total_affected_rows = $count1 + $count2;
Yes checking mysql_affected_rows()==2 is an alternative way from application level.
Its going to be 100% successful(commit) or nothing (rolled back) as you are using proper transactions.
EDIT: You can use ROW_COUNT() function in MySQL to get affected rows from last query as:
USE myDB;
START TRANSACTION;
UPDATE members SET member_active=0 WHERE member_id = 53;
SELECT ROW_COUNT() INTO #count1;
UPDATE member_subscriptions SET subscription_active=0 WHERE member_id = 53;
SELECT ROW_COUNT() INTO #count2;
COMMIT;
ROLLBACK;
then the sum of these should be equals to 2
SELECT ((#count1 + #count2) = 2) AS status;
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.