MySQL Stored procedure to combine multiple select and update - mysql

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.

Related

Assign Query String in a variable

In mySQL stored procedure how can I assign a Query String to a variable, so I can reuse it? In my example I will be using SELECT id FROM audit many times.
CREATE PROCEDURE my_proc()
BEGIN
UPDATE person SET status='Active' WHERE id = (SELECT id FROM audit);
SELECT COUNT(*) FROM (SELECT id FROM audit);
//Multile scenarios the `SELECT id FROM audit` will be used.
END
Something like:
CREATE PROCEDURE my_proc()
BEGIN
myVariable = SELECT id FROM audit;
UPDATE person SET status='Active' WHERE id = (myVariable;
SELECT COUNT(*) FROM (myVariable);
//Multile scenarios the `SELECT id FROM audit` will be used.
END
Is this what you are looking for? Sorry I am not sure what you need.
SELECT #myCount:= count(id) FROM audit;
select #myCount;
Based on your reply, do you need a temporary table to store the ids from the audit and re-use those on the queries?
create temporary table tbl_tmp_audit;
select id from audit;
I am assuming you need this so that you won't join the whole audit columns every time on your succeeding queries.
--first query
UPDATE person AS p
INNER JOIN tbl_tmp_audit t ON p.id = t.id
SET status = 'Active';
--second query
SELECT COUNT(*) FROM tbl_tmp_audit;
Drop temporary table tbl_temp_bookings;

MySQL trigger problem. How to repair it? ERROR 1442

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

I want to update a table in mysql after inserting a row into another table

I have two tables
bill
(id,amount,points)
bill_history
(id,bill_id,amount,points)
When a row is inserted into bill_history , i want to sum up the amount and points from the bill_history table and it should be updated in the bill table according to the bill_id
Try This Way :
INSERT INTO YourTable(columns....)
VALUES(..........)
SET v_lastinsertedrecord = LAST_INSERT_ID()
UPDATE YourTable SET (COLUMNS='value') WHERE id=#lastinsertedrecord
You can use a TRIGGER:
DELIMITER |
CREATE TRIGGER ins_bill_history AFTER INSERT ON bill_history
FOR EACH ROW
BEGIN
UPDATE bill
SET points = (SELECT SUM(points) FROM bill_history WHERE bill_history.bill_id = NEW.bill_id),
amount = (SELECT SUM(amount) FROM bill_history WHERE bill_history.bill_id = NEW.bill_id)
WHERE bill.id = NEW.bill_id;
END;
|
Another solution would be to use a VIEW to SUM the points and amount on the fly:
CREATE VIEW v_bill AS
SELECT bill.*, SUM(bh.points) AS 'points', SUM(bh.amount) AS 'amount'
FROM bill b INNER JOIN bill_history bh ON b.id = bh.bill_id
GROUP BY b.id
Note: In case of using the VIEW you have to remove the columns points and amount on table bill.
You can simply create one trigger AFTER INSERT on bill_history table.
And in this trigger you can wrote logic to update SUM(AMOUNT) AND SUM(POINT) in bill table.

Updating 180k rows via MySQL stored procedure & function is too slow - how to speed up

I have the following stored procedure:
CREATE DEFINER=`ST`#`%` PROCEDURE `CalculateCheapestPriceALL`()
BEGIN
UPDATE
tickets
SET
tickets.Cheapest = GetCheapestTicket(tickets.STPerformerID, tickets.STVenueID, tickets.FeedID);
END
The function GetCheapestTicket is as follows:
CREATE DEFINER=`suprtickets`#`%` FUNCTION `GetCheapestTicket`(performerID INT(11), venueID INT(11), feedID INT(11)) RETURNS decimal(10,2)
BEGIN
DECLARE TicketPrice DECIMAL(10,2);
SET TicketPrice =
IFNULL((
SELECT
MIN(tickets.Price)
FROM
tickets
WHERE
tickets.STPerformerID = performerID
AND
tickets.STVenueID = venueID
AND
tickets.FeedID = feedID
AND
tickets.Price > 0
),0);
RETURN TicketPrice;
END
Running the stored procedure currently takes about 10 minutes, and I'm looking for ways to speed this up.
The following image shows a sample of the data:
The idea behind the stored procedure is to find the cheapest price for the same STPerformerID and STVenueID, and then update this in the Cheapest column. So then I can quickly look up the lowest price for each peformer and venue.
There are about 20k individual Perfomers, and a similar amount of Venues.
Thanks for your help.
Your basic problem is that you are running the query to find the lowest price over again for every row, which is very inefficient.
If you combine the two queries into one query. it will execute significantly faster:
UPDATE tickets AS t1
JOIN (SELECT STPerformerID, STVenueID, STFeedID, MIN(Price) AS cheapest
FROM tickets
WHERE Price > 0
GROUP BY STPerformerID, STVenueID, STFeedID) AS t2
USING (STPerformerID, STVenueID, STFeedID)
SET t1.Price = t2.cheapest
To make it perform well, make sure you have a composite index on (STPerformerID, STVenueID, STFeedID) (or at least some subset of these columns).

Comparing Dates For Multiple Entries

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.