I have 3 tables, tbl_image, tbl_vehicle_image and tbl_vehicle
tbl_vehicle_image resolves a many-many relationship between tbl_image and tbl_vehicle
tbl_vehicle has a last_modified_date
How do I create a trigger that, when I change for example tbl_image.img_lnk, uses tbl_vehicle_image to find all records in tbl_vehicle that use that image, and set their last_modified_date to NOW()?
CREATE TRIGGER `trig_after_image_update` AFTER UPDATE ON `tbl_image`
FOR EACH ROW
if old.img_lnk<>NEW.img_lnk
then
update tbl_vehicle set last_modified_date=NOW() where id in (select vehicle_id from tbl_vehicle_image where image_id=OLD.id);
end if;
I don't have all field name of your table so change those. I have used id as primary key for corresponding table.
You can do this:
DELIMITER $$;
create TRIGGER UpdateLastmodifiedDate AFTER UPDATE ON tbl_image
FOR EACH ROW
BEGIN
UPDATE tbl_vehicle v
INNER JOIN tbl_vehicle_image vi ON v.vehicleId = vi.vehicleID
INNER JOIN tbl_image i ON vi.imageid = i.id
SET v.lastmodified_date = NOW()
WHERE i.img_lnk = NEW.img_lnk;
END$$
Related
I am working on converting a T-SQL stored procedure into MySQL. I am not familiar with T-SQL and am working on becoming more familiar with temp tables and stored procedures. Thanks for your help in advance.
The T-SQL original looks like this (EDIT: note this is only a portion of the original procedure used to produce a report):
DROP TABLE IF EXISTS #accounts;
SELECT d.data_id
,p.pp_name AS name
,CONVERT(tinyint,1) AS flag
,d.pd_date
,CONVERT(char(6),pd_date,112) AS date_period
,CONVERT(varchar(3),0) AS n_phones
INTO #accounts
from table_detail d
JOIN table_pool p ON d.pp_id = p.pp_id
JOIN table_type t ON p.pp_type_id = t.pp_type_id
JOIN Inventory i ON d.data_id = i.data_id
JOIN Product pr ON i.product_id = pr.product_id
WHERE pp_name IN (SELECT name FROM Sandbox..desired_sandbox)
AND DATEDIFF(MONTH,pd_date,GETDATE()) < 3
UPDATE a
SET a.flag = 0
FROM #accounts a
JOIN table_detail d ON a.data_id = d.data_id
JOIN table_pool p ON d.pp_id = p.pp_id
WHERE d.pd_date < a.pd_date
AND pp_name != 'error';
My current update is below. Do I need to wrap this in a CREATE TEMPORARY TABLE IF NOT EXISTS accounts AS (<insert query here>) instead of the INTO #accounts?
SELECT d.data_id
,p.pp_name AS name
,CONVERT(tinyint,1) AS flag
,d.pd_date
,DATE_FORMAT(pd_date,'%Y%m%d') AS date_period
,CONVERT(varchar(3),0) AS n_phones
FROM table_detail d
JOIN table_pool p ON d.pp_id = p.pp_id
JOIN table_type t ON p.pp_type_id = t.pp_type_id
JOIN Inventory i ON d.data_id = i.data_id
JOIN Product pr ON i.product_id = pr.product_id
WHERE pp_name IN (SELECT name FROM Sandbox..desired_sandbox)
AND TIMESTAMPDIFF(MONTH,pd_date,NOW()) < 3
Then do something like this assuming the syntax is right:
UPDATE accounts a -- Is this the correct way to add an alias and update the temp table?
JOIN table_detail d ON a.data_id = d.data_id
JOIN table_pool p ON d.pp_id = p.pp_id
SET a.flag = 0
WHERE d.pd_date < a.pd_date
AND pp_name != 'error';
Finally, I assume I could follow this post to wrap the final query into a stored procedure, correct? To summarize the code in the post:
drop procedure if exists procedure_name;
DELIMITER $$
create procedure procedure_name ()
BEGIN
DROP TEMPORARY TABLE IF EXISTS accounts;
CREATE TEMPORARY TABLE accounts AS (
SELECT...
FROM...
WHERE...
;
)
UPDATE accounts
JOIN ...
JOIN ...
SET...
WHERE...;
DROP TEMPORARY TABLE accounts; -- otherwise it survives the stored proc call
END
$$ -- signify end of block
DELIMITER ; -- reset to default delimiter
I wanted to post the solution that finally worked for me for others that might be having the same issue. The code below resolves this.
DROP PROCEDURE IF EXISTS procedure_name;
DELIMITER $$
CREATE PROCEDURE procedure_name ()
BEGIN
DROP TEMPORARY TABLE IF EXISTS accounts;
CREATE TEMPORARY TABLE accounts AS (
SELECT d.data_id
,p.pp_name AS name
,1 AS flag
,d.pd_date
,DATE_FORMAT(pd_date,'%Y%m%d') AS date_period
,CONVERT(varchar(3),0) AS n_phones
FROM table_detail d
JOIN table_pool p ON d.pp_id = p.pp_id
JOIN table_type t ON p.pp_type_id = t.pp_type_id
JOIN Inventory i ON d.data_id = i.data_id
JOIN Product pr ON i.product_id = pr.product_id
WHERE pp_name IN (SELECT name FROM Sandbox..desired_sandbox)
AND TIMESTAMPDIFF(MONTH,pd_date,NOW()) < 3
);
-- Update the temp table based on specified criteria
UPDATE accounts
JOIN ...
JOIN ...
SET...
WHERE...;
-- Create final Query for report
SELECT ...
FROM accounts
WHERE ...
GROUP BY ... -- whatever you need for final query
DROP TEMPORARY TABLE accounts; -- otherwise it survives the stored proc call
END
$$ -- signify end of block
DELIMITER ; -- reset to default delimiter
However, it is important to note the limits of MySQL temporary tables. Although I did not indicate it in my original post, later, I was attempting to join the temporary table onto itself. I needed to follow the suggestion outlined here. Essentially, if you need to refer to a temp table with itself you need to make a copy of the temp table: CREATE TEMPORARY TABLE accounts2 AS (SELECT * FROM accounts). Then you can join a temp table to itself.
I am new to triggers but have coded this one
DELIMITER $$
CREATE TRIGGER stockupdate
AFTER INSERT ON inventory.orderdetails
FOR EACH ROW
BEGIN
UPDATE inventory.stockitem s
INNER JOIN inventory.OrderDetails d ON s.ID = d.Item
INNER JOIN inventory.orders o ON ebayOrderNumber = d.OrderNumber
SET s.`Sold Date` = o.`Order Date`, s.EbayOrderNumber = o.ebayOrderNumber, s.`Sale Price` = d.Price
WHERE s.ID = d.Item;
END$$
DELIMITER ;
Currently it does not update table stockitem as expected. Is there anything glaringly obvious that I have done wrong please?
Many thanks for looking.
That's because your join returns all or most records from oderDetails and oders table and you are not supressing sql_safe_updates safety feature.
You are definitely missing table alias in o ON ??.ebayOrderNumber = d.OrderNumber. Besides, WHERE s.ID = d.Item; is redundant as your table joins already do that. Your Where condition should be more explicit and tell which stock item to update.
DELIMITER $$
CREATE TRIGGER stockupdate AFTER INSERT ON inventory.orderdetails FOR EACH ROW
BEGIN
UPDATE
(inventory.stockitem s
INNER JOIN inventory.OrderDetails d ON s.ID = d.Item)
INNER JOIN inventory.orders o ON o.ebayOrderNumber = d.OrderNumber
SET
s.`Sold Date` = o.`Order Date`, -- update the stock
s.EbayOrderNumber = o.ebayOrderNumber,
s.`Sale Price` = d.Price
WHERE
d.orederNumber = NEW.OrderNumber, -- From this order
d.Item = NEW.item; -- and this item id
END$$
DELIMITER ;
Having said that, I do not understand why would you want to update the stock table with a sold price? orderDetails already contains those for you and what if you have many quantity for a single stock? i.e 100 Dell laptops. Surely you don't have 100 records for each Dell laptop in your stock item? and updating each record with sold price? Anyway i leave that up to you..
If an account id exists in table_subscription, I want to set table_account.account_do_not_email = 1, else leave it alone. We are getting rid of the subscription table and just using this method.
The code I currently have works for updating the very first column it finds but not all of them..
UPDATE table_account a
SET account_do_not_email = 1
WHERE EXISTS (SELECT 1 FROM table_subscription b WHERE b.account_id = a.account_id)
You can use join to do this
update table_account a
join table_subscription b on b.account_id = a.account_id
set a.account_do_not_email = 1
If you have have that particular account_id in both tables then table_account table will be updated
UPDATE table_account a
INNER JOIN table_subscription ts
ON ts.account_id = a.account_id
SET account_do_not_email = 1
You can do it like this too:
update table_account
set account_do_not_email = 1
where account_id in (select account_id from table_subscription)
delimiter $$
drop procedure if exists getEmptySeats $$
create procedure getEmptySeats(flight_number char(5),flight_date date)
begin
select seatingID as Seats, concat(Seats.rowNumber, Seats.seatNumber) as Seat
from Seating
where
aircraftID = aircraft_id and
seatID not in
( Select seatID from Seating
inner join Seats on Seating.seatID = Seats.seatID
inner join Booking on Seating.bookingNumber = Booking.bookingNumber
inner join Flights on Booking.flightCode = Flights.flightCode
inner join FlightSchedule on Flights.flightNumber = FlightSchedule.flightNumber
where flightNumber = flight_number and flightDate = flight_date)
order by seatingID;
end $$
ORDER BY RAND()
LIMIT 1
delimiter ;
The procedure is suppose to give a random seat in a specific airplane.
I have no idea what is wrong and I have searched the internet for so long and haven't found any thing that helped.
When I call the procedure it gives this:
Error Code: 1054. Unknown column 'Seats.rowNumber' in 'field list'
Here is the Seats table:
seatID INT(11)
rowNumber TINYINT(4)
seatNumber CHAR(1)
seatPlacement VARCHAR(15)
plainID CHAR(6)
You need to join it with Seats table. The one used as a subquery can not be accessed directly
As #Madhivanan mentioned, you need to join it with the Seats table.
There were also a few ambiguous columns which needed fixing (prefixing with the table name usually is the easiest answer unless you give the table an alias)
delimiter $$
drop procedure if exists getEmptySeats $$
create procedure getEmptySeats(flight_number char(5),flight_date date)
begin
select seatingID as Seats, concat(Seats.rowNumber, Seats.seatNumber) as Seat
from Seating
inner join Seats on Seating.seatID = Seats.seatID
where
aircraftID = aircraft_id and
seating.seatID not in
( Select seating.seatID from Seating
inner join Seats on Seating.seatID = Seats.seatID
inner join Booking on Seating.bookingNumber = Booking.bookingNumber
inner join Flights on Booking.flightCode = Flights.flightCode
inner join FlightSchedule on Flights.flightNumber = FlightSchedule.flightNumber
where Flights.flightNumber = flight_number and flightDate = flight_date)
order by seatingID;
end $$
ORDER BY RAND()
LIMIT 1
delimiter ;
I'm new to triggers and am getting "multiple triggers with the same action time and event for one table" error.
I have created an AFTER Update and an AFTER Delete which are two separate action time/events so I am not really sure why I would be getting the error.
Here is my query:
CREATE TRIGGER `new_enrolment` AFTER INSERT ON `mdl_user_enrolments` FOR EACH ROW BEGIN
INSERT INTO c_master (
ud,
firstname,
lastname,
email,
username,
cid,
course
)
SELECT
mdl_user.id AS uid,
mdl_user.firstname,
mdl_user.lastname,
mdl_user.email,
mdl_user.suspended,
mdl_user.username,
mdl_enrol.courseid AS cid,
mdl_course.fullname AS course
FROM mdl_user_enrolments INNER JOIN mdl_enrol ON mdl_user_enrolments.enrolid = mdl_enrol.id
INNER JOIN mdl_course ON mdl_enrol.courseid = mdl_course.id
INNER JOIN mdl_user ON mdl_user.id = mdl_user_enrolments.userid
WHERE userid = NEW.userid;
END;
CREATE TRIGGER `remove_enrolment` AFTER DELETE ON `mdl_user_enrolments` FOR EACH ROW BEGIN
SELECT mdl_enrol.courseid,
mdl_user_enrolments.userid,
mdl_user_enrolments.enrolid
FROM mdl_user_enrolments INNER JOIN mdl_enrol ON mdl_user_enrolments.enrolid = mdl_enrol.id
WHERE mdl_user_enrolments.enrolid = OLD.enrolid
DELETE FROM c_master
WHERE uid = OLD.userid AND mdl_enrol.courseid;
END;
Since I am new to all of this I am probably missing something simple.
Brian, probably you've been adding and removing the same trigger a few times in your table and you have forgotten to remove it last time before create it again. Get sure you've removed it before create again using
DROP TRIGGER [IF EXISTS] [schema_name.]trigger_name
and then
CREATE TRIGGER ....
Documentation here.