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..
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 have the following Trigger:
delimiter |
CREATE TRIGGER DES1actualizarConsultaR_update
AFTER UPDATE ON ranking
FOR EACH ROW
BEGIN
UPDATE player P,
(SELECT
J.player_id AS jugador_id,
SUM(ranking_points) AS PuntosTotales
FROM
player J
INNER JOIN ranking R ON R.player_id = NEW.player_id
GROUP BY J.player_id) AS TD
SET
P.totalPuntos = TD.PuntosTotales
WHERE
P.player_id = TD.jugador_id;
UPDATE player P,
(SELECT
J.player_id AS JnumUno, COUNT(*) AS NumVeces1
FROM
player J
INNER JOIN ranking R ON R.player_id = NEW.player_id
WHERE
R.ranking = '1'
GROUP BY J.player_id) AS TD
SET
P.vecesNum1 = TD.NumVeces1
WHERE
P.player_id = TD.JnumUno;
END |
I'am trying to execute this update:
UPDATE ranking
SET
ranking_points = (ranking_points + 10)
WHERE
player_id IN (SELECT
P.player_id
FROM
player P,
tourney T,
tmatch M
WHERE
T.tourney_name LIKE 'Madrid%'
AND T.tourney_date BETWEEN '2017-01-01' AND '2018-12-31'
AND (M.round = 'F' OR M.round = 'SF')
AND P.player_id = M.winner_id
AND M.tourney_id = T.tourney_id);
But I have this error:
Error Code: 1442. Can't update table 'player' in stored
function/trigger because it is already used by statement which invoked
this stored function/trigger.
How can I do the update query?
I´m using MYSQL.
It happens because you are have a jointure on the ranking table in the TRIGGER's UPDATE statement.
Even if you aren't updating the ranking table itself, MySQL doesn't like it.
You have to get around it by doing a stand-alone SELECT query first to compute the player's points, save those points in a variable, and then use it in your UPDATE of the player table, without referencing the ranking table
Here's the idea:
delimiter |
CREATE TRIGGER DES1actualizarConsultaR_update
AFTER UPDATE ON ranking
FOR EACH ROW
BEGIN
DECLARE vPuntosTotales INT;
DECLARE vNumVeces1 INT;
SELECT SUM(ranking_points) AS PuntosTotales INTO vPuntosTotales
FROM ranking
WHERE player_id = NEW.player_id;
UPDATE player SET totalPuntos = vPuntosTotales WHERE player_id = NEW.player_id;
-- NOT SURE IF THIS ONE IS CORRECT
SELECT COUNT(*) AS NumVeces1 INTO vNumVeces1
FROM ranking R
WHERE R.ranking = '1' AND R.player_id = NEW.player_id;
UPDATE player SET vecesNum1 = vNumVeces1 WHERE player_id = NEW.player_id;
END |
you should review my queries because I don't know exactly your table structure and I might be wrong in my SELECTs, especially in the second one
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.
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$$