I don't know how to make the trigger work. I already managed to make it pass with no errors, but now I have the problem from the title.
Here is a photo of a schema of given database:
Thanks a lot for any help or ideas!
/* Trigger do liczenia Total w Platnosciach */
DELIMITER //
CREATE TRIGGER t_Payments AFTER INSERT ON Payments
FOR EACH ROW
BEGIN
/* Ciagniemy numer rezerwacji (ZALOZENIE: TYLKO JEDNO ZRODLO ROBIENIA REZERWACJI) */
SET #bookID=0;
SELECT b.BookID INTO #bookID
FROM Bookings b
ORDER BY b.BookID DESC
LIMIT 1;
/* Calosc Pokoju */
SET #room=0;
SELECT
TRUNCATE((DATEDIFF(b.DepDate,b.ArrDate)*r.Price),2) INTO #room
FROM Rooms r
INNER JOIN Bookings b ON r.RoomID = b.RoomID
WHERE
b.BookID = #bookID;
/* Calosc Uslug */
SET #serv=0;
SELECT
TRUNCATE(SUM(si.price),2) INTO #serv
FROM Bookings b
INNER JOIN Services se ON b.BookID = se.BookID
INNER JOIN ServInfo si ON se.code = si.code
WHERE
b.BookID = #bookID;
/* Kod wbicia w Payments Total*/
UPDATE Payments
SET Total=((#room)+(#serv))
WHERE PaymentID=#bookID;
END //
DELIMITER ;
ERROR 1442 (HY000): Can't update table 'payments' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
Trigger is supposed to make a calculation how much the reservation will cost.
Later I will try to make the very INPUT of the data in the first place impossible, because inputting 0 or soomething random is pointless if it will be replaced the very second it gets submitted.
Your error says it all: you can't update (rows in) the same table as which you created your trigger for. You can however modify your row that is about to be inserted by:
First, changing your trigger timing from AFTER to BEFORE
Secondly, alter the row that is about te be inserted
with:
CREATE TRIGGER t_Payments BEFORE INSERT ON Payments
FOR EACH ROW
BEGIN
-- Your magic here
SET NEW.Total = ((#room)+(#serv));
END
Related
I am newbie to stored procedure, hence this basic question.
I want to create a table of average sales for last 10 days, then I need to query existing stock and update the stock in the sales table.
This create sales data for last 10 days.
DELIMITER //
CREATE PROCEDURE JDSTOCK()
BEGIN
DROP TABLE IF EXISTS Test1;
Create table Test1 AS
Select
Invoice.BranchID,
Invoice.CustomerName,
InvoiceDetail.ProductMasterID,
Sum(InvoiceDetail.Quantity),
Avg(InvoiceDetail.Quantity) As Avg_Quantity,
0.00 As BranchStock
From
Invoice Inner Join
InvoiceDetail On InvoiceDetail.InvoiceID = Invoice.InvoiceID
Where
Invoice.InvoiceDate >= CurDate() - 10 And
Invoice.CustomerName Like '%BRANCH%'
Group By
Invoice.BranchID,
Invoice.CustomerName,
InvoiceDetail.ProductMasterID ;
END;//
DELIMITER;
2. Step that I want to execute from stored procedure
* Create Stock Table for KTMY */
Select
Stock.BranchID,
Stock.ProductMasterID,
Sum(Stock.CurrentQty) As Sum_CurrentQty,
Branch.BranchName,
Max(Stock.PurchaseDate) As Max_PurchaseDate
From
Stock Inner Join
Branch On Branch.BranchID = Stock.BranchID
Where
Branch.BranchName = 'KTMY'
Group By
Stock.BranchID,
Stock.ProductMasterID,
Branch.BranchName
Having
Sum(Stock.CurrentQty) > 0
3. Third step
*** Update stock in sales table
Update DevTest INNER JOIN DevStock on
DevTest.ProductMasterID = DevStock.ProductMasterID
SET DevTest.EKMStock = DevStock.Sum_CurrentQty;
How will I achieve this in stored procedure.
Thanks in advance.
IF(room_status.check_out<date_in) THEN
UPDATE room SET room.status='AVAILABLE';
ELSE
UPDATE room SET room.status='BOOKED' ;
END IF
You can't access room_status.check_out outside a query that selects from the room_status table.
If you want to do this in all rows, put the condition inside the UPDATE that joins the tables.
UPDATE room AS r
JOIN room_status AS rs ON r.id = rs.room_id
SET r.status = IF(rs.check_out < date_in, 'AVAILABLE', 'BOOKED')
I am executing this query:
INSERT INTO Takes(Student_SSN_N,Exam_Couse_ID,Exam_ID)
SELECT "xxx", "y", "z"
FROM Student as S, Exam as E
WHERE EXISTS (SELECT *
FROM Follows
WHERE S.Student_SSN = "xxx"
AND S.Student_SSN = Follows.Student_SSN_N
AND Follows.Course_ID = y
)
AND EXISTS (SELECT *
FROM Follows
WHERE Follows.Course_ID = y
AND E.Course_ID = y
AND E.Exam_ID = z
)
(Values x, y, z are given by the user in a java application)
It works, the student that has to take the exam is correctly added to the table after checking if he actually follows the course and if the exam relates to the course itself. I'm just performing a check on the Exam table.
In the Exam table I maintain a "student number", which tells you how many students need to take the exam. I want to update this number every time I insert a new student in the Takes table. So I thought about using a trigger, and I wrote this:
DELIMITER $$
CREATE TRIGGER `Takes_after_insert` AFTER INSERT ON `Takes`
FOR EACH ROW
UPDATE Exam
SET Exam.Student_Num = Exam.Student_Num + 1
WHERE Takes.Course_ID = Exam.Course_ID and
Take.Exam_ID = Exam.Exam.ID;
It's a simple trigger (I haven't studied anything more complex yet). But I get this error:
Error Code: 1442. Can't update table 'Exam' in stored
function/trigger because it is already used by statement which invoked
this stored function/trigger.
(I also tried pointing the trigger to a different table just to see if the logic of it was wrong, and it worked)
Ok, I can't update the Exam table because I'm using it in the query that launches the trigger. But the how can I update the table?
You don't need the exam table in the insert. In fact, the logic seems quite hard to follow, but I think you are just checking two conditions and inserting one row. You can check the conditions as subqueries in the FROM and use CROSS JOIN . . . if either returns no rows, then the CROSS JOIN returns no rows.
So, I think this insert does what you want:
INSERT INTO Takes(Student_SSN_N, Exam_Couse_ID, Exam_ID)
SELECT "xxx", "y", "z"
FROM (SELECT 1
FROM Follows f
WHERE f.Student_SSN_N = "xxx" AND
f.Course_ID = y AND
) s CROSS JOIN
(SELECT 1
FROM Follows f
WHERE f.Course_ID = y AND
E.Exam_ID = z
) e;
The structure of the Follows table is quite curious, containing exams, students, and courses. But that is not the question you are asking.
As mentioned in the comment, you want new in the trigger rather than exams.
im creating a small hire car system and i want a stored procedure that takes in a date and checks to see which cars are available then. I've got the compare working but if a car has more than one contract and one of the contracts isn't for the entered date but another is it says the car is available. Below is my procedure so far
delimiter //
create procedure allAvailableVehicles(req varchar(15))
BEGIN
select distinct vehicles.vehicleID as "Vehicle ID", vehicles.Make as "Make", vehicles.Model as "Model" from vehicles
left outer join contracts
on vehicles.vehicleID=contracts.vehicleID
where cast(req as date) not between hiredFrom and hiredUntill
or contractID is unknown
order by vehicles.vehicleID;
end
//
delimiter ;
This is a good opportunity to use not exists:
select v.*
from vehicles v
where not exists (select 1
from contracts c
where c.VehicleId = v.VehicleId and
cast(req as date) between hiredFrom and hiredUntil
);
Note: you should not need to cast req as a date, because it should already be stored as a date in the database (unless req also has a time component).
A better way to write the stored procedure is:
delimiter //
create procedure allAvailableVehicles(p_req date)
begin
select v.*
from vehicles v
where not exists (select 1
from contracts c
where c.VehicleId = v.VehicleId and
p_req between hiredFrom and hiredUntil
);
end //
delimiter ;
Use built-in types for date/times. Also, name your parameters to distinguish them from columns.
I am having some problems with my TRIGGER:
CREATE TRIGGER "tblSettingTable_INSERT"
ON dbo.tblSettingTable
FOR INSERT
AS
INSERT INTO dbo.tblSettingReportParameter (tableName, columnName, columnCaption)
SELECT tableName = CAST(OBJECT_NAME(c.object_id) AS varchar(100)),
columnName = CAST(c.name AS varchar(100)),
columnCaption = CAST(ex.value AS varchar(100))
FROM sys.columns c
LEFT OUTER JOIN sys.extended_properties ex
ON ex.major_id = c.object_id
AND ex.minor_id = c.column_id
AND ex.name = 'MS_Caption'
INNER JOIN inserted ON OBJECT_NAME(c.object_id) = inserted.tableName
WHERE OBJECTPROPERTY(c.object_id, 'IsMsShipped')=0
AND OBJECT_NAME(c.object_id) = inserted.tableName
I am trying the get some column properties from a table and INSERT it into dbo.tblSettingReportParameter but I get this thrown at my face: "Key column information is insufficient or incorrect. Too many rows were affected by update."
What am I doing wrong? Using MS-SQL 2008 RS.
Thanks,
Stefan
Should be fixed if you add SET NOCOUNT ON to the trigger.
The xx rows returned is confusing Access (which I assume issues the INSERT to SQL Server of course based on the tags for the question)