MySql calculating rows based on previous row value - mysql

CREATE PROCEDURE available_rooms(
hotelname_param VARCHAR(45),
date_param DATE)
BEGIN
IF date_param IS NULL THEN -- if the booking date is null
SIGNAL SQLSTATE '22003' -- signalling error
SET MESSAGE_TEXT = 'the booing date should not be null',
MYSQL_ERRNO = 1264;
END IF;
SELECT h.Hotel_id AS HotelID,hotelname_param AS HotelName,((h.Floor_count) * (h.Roomsperfloor)) AS TotalRooms,
g.Guest_firstname AS Guestname,b.Room_count AS RoomsBooked,
(((h.Floor_count) * (h.Roomsperfloor)) - b.Room_count) AS AvailableRooms
FROM hotel h
JOIN guests g ON h.Hotel_id = g.Hotel_id
JOIN booking b ON g.Guest_id = b.Guest_id
WHERE b.BookingDate = date_param;
END
CALL available_rooms('Grand Central Inn', '2018-01-11')
when I call the procedure its displaying output as THIS
So the available rooms of first row should be used for the next row calculation, but I am not able to get that.Can anyone help me out

Related

Logical problems in SQL procedure

I'm writing a procedure that is supposed to do the following:
Create a procedure that adds item (s) to an order.
The number of what is in stock for the item must also be reduced by the same number.
If no_of_items are more than what is in stock, the highest possible should be added so that stock is zero.
The procedure must respond with a status of how many items have been added and warn or inform if the number was not as many as desired.
If there are no items in stock, information must also be provided.
Check must also be done so that the order ID and item ID are available.
It should only be possible to add items to an order if it has shipping_status set to "open".
The procedure I have written looks as following:
DELIMITER //
CREATE PROCEDURE add_item_to_order(order_id INT, item_id INT, no_of_items INT)
BEGIN
IF order_id IN (SELECT number FROM Orders WHERE Orders.status = "open") THEN
IF item_id IN (SELECT number FROM Items WHERE Items.stock = 0) THEN
SIGNAL SQLSTATE "45000" SET MESSAGE_TEXT = "item is not in stock";
END IF;
SET #stock = (SELECT Items.stock FROM Items WHERE Items.number = item_id);
IF no_of_items <= #stock THEN
WHILE no_of_items > 0 DO
INSERT INTO orders_items (o_id, i_id) VALUES (order_id, item_id);
UPDATE Items SET Items.stock = (Items.stock - no_of_items) WHERE Items.number = item_id;
SET no_of_items = no_of_items - 1;
END WHILE;
SELECT (no_of_items) AS "Item has been added. Amount of items: " ;
END IF;
IF no_of_items > #stock THEN
WHILE no_of_items > 0 DO
INSERT INTO orders_items (o_id, i_id) VALUES (order_id, item_id - (item_id * no_of_items));
UPDATE Items SET Items.stock = (Items.stock - no_of_items) WHERE Items.number = item_id;
SET no_of_items = (no_of_items -1);
END WHILE;
SIGNAL SQLSTATE "45000" SET MESSAGE_TEXT = "Enough is not in stock. Biggest possible amount of items has been added" ;
END IF;
ELSE SIGNAL SQLSTATE "45000" SET MESSAGE_TEXT = "Order must have status Open";
END IF;
END //
DELIMITER ;
The problem is that somethings are logically wrong because the output is not as expected. If I try to call it with: CALL add_item_to_order(7, 5, 2), it should add two rows because no_of_items are 2, but it only adds one row. I need help with figuring out how I should write instead so it gives the correct output.
Also, if anyone has advice on how I can improve this query, I would very much appreciate it. I have written this procedure for a couple of days and can't figure out if its good written or bad.

SQL PROCEDURE ISSUE,not sure on placement of data

Write a stored procedure that updates the weekly duty roster for an employee and allocates him/her a maximum of 5 work shifts in a given branch. To update the roster, the procedure ensures that:
i. The employee has an existing roster allocated to her/him. In case there is no existing roster for a given employee, the procedure doesn’t update the roster, rather prints an appropriate error message.
ii. The day of current roster is shifted by one day in the updated roster. For instance, if the current roster for an employee shows work shifts from Monday to Friday, then the updated roster will allocate work shifts from Tuesday to Saturday. For simplicity, we will assume that the type and number of work shifts allocated to an employee remain
same from week to week unless an exception occurs such as overallocation. However, the manager may wish to add any extra work shifts to an employee manually.
iii. A warning message is displayed in case the allocated hours of work for an employee exceeds the standard hours of work (35 hours per week).
any help is appreciated having a lot of trouble getting this right.. MYSQL
DELIMITER //
DROP PROCEDURE IF EXISTS updateRoster
CREATE PROCEDURE UpdateWeeklyRoster (IN e CHAR(8), IN b INT)
BEGIN
-- variable declaration
DECLARE WORKING_HOURS INT(35);
DECLARE Updated_Working_Shift_ID INT;
-- cursor declaration
DECLARE c1 CURSOR FOR
EmployeeID,BranchID,WorkingShiftID;
DECLARE CONTINUE HANDLER FOR NOT FOUND set finished = 1;
-- check whether the employee exists or not
SELECT EmployeeID into e
FROM DutyRoster
WHERE EmployeeID = e;
IF e IS NULL THEN
SIGNAL SQLSTATE '45000' set MESSAGE_TEXT = 'THERE IS EXISTING ROSTER';
ELSE
-- actual part
-- delete existing tuples relevant to the given employee and branch id from the Duty Roster table
OPEN c1;
-- execute a loop
REPEAT
FETCH c1 into .... , ....., .....;
-- find the workingShiftWeekDay: assign appropriate values into Current_Week_Day
-- Find the Updated_Week_Day
SET Updated_Week_Day =
CASE Current_Week_Day
WHEN Week_day='MONDAY' THEN Updated_Week_Day='TUESDAY';
WHEN 'TUESDAY' THEN 'WEDNESDAY';
WHEN 'THURSDAY' THEN 'FRIDAY';
WHEN 'FRIDAY' THEN 'SATURDAY';
WHEN 'SATURDAY' THEN 'SUNDAY';
WHEN 'SUNDAY' THEN 'MONDAY';
ELSE .....
END CASE;
-- Find the current_duty_type
-- for the updated_week_day, find an appropriate working shift id
SELECT dutyType into WorkingShiftID
FROM WorkingShift
WHERE EmployeeID AND dutyType = CurrentDutyType;
-- insert the new record
INSERT INTO DutyRoster VALUES (e,b,Updated_Working_Shift_ID);
UNTIL ........;
END REPEAT;
CLOSE c1;
-- Checking whether an employee works for more than 35 hours
SELECT HOUR(TIMEDIFF(WorkingShiftEndTime,WorkingShiftStartTime)) INTO TOTAL, WORKING_HOURS
from WorkingShift, DutyRoster
WHERE DutyRoster, WorkingShiftID = WorkingShift, WorkingShiftID
AND EmployeeID = e;
IF TOTAL, WORKING HOURS > 35 THEN
SIGNAL SQLSTATE '45001' SET MESSAGE_TEXT = 'Employee is working over 35 hours....';
END IF;
END IF;
END
DELIMITER ;
DELIMITER //

SAP b1 transaction Nofitication to block sales order documents with customers who has Over Credit

Situation: A customer has 50K credit limit, and 0 Balance. The customer ordered greater than its credit limit(ex. 54,000). So a transaction notification must be triggered.
Problem: Get customer creditLimit amount; get customer order balance;
What i have tried so far:
IF #object_type='17' AND #transaction_type IN ('A','U')
BEGIN
Declare #CredLimit As nvarchar(250)
SET #CredLimit= (SELECT T0.CreditLine FROM OCRD T0
WHERE T0.CardCode=#list_of_cols_val_tab_del)
IF (
SELECT (T0.DocTotal+T1.Balance) FROM ORDR T0 INNER JOIN OCRD T1 ON T0.CardCode=T1.CardCode
WHERE DocStatus='O' AND T1.DocEntry=#list_of_cols_val_tab_del) > #CredLimit
BEGIN
Set #error = -1
SET #error_message = 'Business Partner is Over Credit Limit! Save this document as DRAFT, thank you'
END
END
The SAP b1 has its own system define notification on credit limit, but we do not want to answer its "Yes or No", we just want to inform the encoder of SO that the Sales order is now making the customer Over CL and therefore save the SO as Draft.
IF #object_type='17' AND #transaction_type IN ('A','U')
BEGIN
Declare #CredLimit As nvarchar(250)
SET #CredLimit= (SELECT T0.CreditLine FROM OCRD T0
WHERE T0.CardCode=(SELECT CardCode FROM ORDR
WHERE DocEntry = #list_of_cols_val_tab_del)
IF (
SELECT (T0.DocTotal+T1.Balance)
FROM ORDR T0
INNER JOIN OCRD T1 ON T0.CardCode=T1.CardCode
WHERE DocStatus='O' AND T1.DocEntry=#list_of_cols_val_tab_del) > #CredLimit
BEGIN
Set #error = -1
SET #error_message = 'Business Partner is Over Credit Limit! Save this document as DRAFT, thank you'
END
END
The issue is that in the SET #CredLimit statement was checking if T0.CardCode was equal to #list_of_cols_val_tab_del, which is actually the DocEntry of the order. Actually, now that I look at it, you could even do something like
IF #object_type='17' AND #transaction_type IN ('A','U')
BEGIN
IF EXISTS (
SELECT T0.DocEntry
FROM ORDR T0
INNER JOIN OCRD T1 ON T0.CardCode=T1.CardCode
WHERE DocStatus='O'
AND T1.DocEntry=#list_of_cols_val_tab_del
AND (T0.DocTotal + T1.Balance) > T1.CreditLine)
BEGIN
Set #error = -1
SET #error_message = 'Business Partner is Over Credit Limit! Save this document as DRAFT, thank you'
END
END
In this second version, you completely ignore the unnecessary step of declaring a variable.

mySQL finding available book and loaning it

I have created a library system and i'm trying to set up a procedure which allows you to enter an isbn and student number and from that it checks the database to see if the book is available if it is, book it. If not then give an error message.
My tables are as follows:
book - pk_isbn, author, title
copy - pk_code, duration, fk_isbn
loan - fk_code, fk_no, pk_taken, due, return_date
student - pk_no, name, school, allowedtobook
Here is what i currently have code wise *some is just sorta pseudo code i guess as it doesn't work at all currently.
DELIMITER $$
CREATE PROCEDURE issue_loan (IN book_isbn CHAR(17), IN stu_no INT)
BEGIN
DECLARE availablebooks INT;
DECLARE allowedtobook BIT;
SET availablebooks = (SELECT DISTINCT
c.isbn
FROM
loan l
INNER JOIN
student s ON l.no = s.no
INNER JOIN
copy c ON l.code = c.code
WHERE
return_date IS NOT NULL);
IF(availablebooks = book_isbn) AND s.embargo = 0 THEN
INSERT INTO loan VALUES
(code, stu_no, CURDATE(), CURDATE()+c.duration,'');
ELSE
SIGNAL SQLSTATE '450000' SET MESSAGE_TEXT ='no Books Available';
END IF;
END$$
The part which return_date IS NOT NULL should be correct as it finds any books which haven't been returned yet. Meaning they're currently booked out.
You can't set a variable to a query result set, a variable can only hold one value. You should simply add the comparison with book_isbn and s.embargo = 0 to the query.
SET #book_available = (SELECT COUNT(*)
FROM loan l
INNER JOIN student s ON l.no = s.no
INNER JOIN copy c ON l.code = c.code
WHERE c.fk_isbn = book_isbn AND s.embargo = 0 AND l.return_date IS NULL);
IF #book_available
THEN
INSERT INTO loan (fk_code, fk_no, pk_taken, due, return_date)
VALUES (code, stu_no, CURDATE(), CURDATE()+c.duration,'');
ELSE SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT ='no Books Available';
END IF

How can I get this stored procedure to execute a CALL when the condition is not equal?

I have a quick question about MySql. I have this simple store procedure, that I would like to make a CALL to two store procedures when the condition is met.
The variable #SDOuser is assigned the User ID when the access level is 10 and the timestamp evaluates to the login time of between now and 2 seconds ago. Once I have this set, I then want to use it as the condition for my IF block. Here lies the issue, it works fine when the first block stays TRUE and nothing follows. But, I need the Users who have access level that is less than 10 and it does not seem to like the negating the condition to get to that.
Here is the code:
DROP PROCEDURE `getPositionGrid`//
CREATE DEFINER=<some name> PROCEDURE `getPositionGrid`()
BEGIN
set #SDOuser = (SELECT DISTINCT(uu.uu_id) FROM tbl_logins ul
INNER JOIN tbl_users uu
ON ul.ul_username = uu.uu_email
inner join tbl_access_level al
on al.al_id = uu.al_id
inner join tbl_positions up
on up.up_id = uu.up_id
inner join tbl_departments ud
on up.ud_id = ud.ud_id
WHERE ul.ul_created BETWEEN NOW() - INTERVAL 2 SECOND AND NOW());
set #CurrUser = (select uu_id from tbl_users where al_id = 10 AND uu_id = #SDOuser);
set #CurrUser1 = (select uu_id from tbl_users where al_id < 10 AND uu_id != #SDOuser);
IF(#CurrUser) THEN
BEGIN
CALL getPositionGridSDO();
END;
END IF;
IF(#CurrUser1) THEN
BEGIN
CALL getPositionGridALL();
END;
END IF;
END
//
Try this:
IF (#CurrUser IS NOT NULL) THEN
BEGIN
CALL getPositionGridSDO();
END;
END IF;
IF(#CurrUser1 IS NOT NULL) THEN
BEGIN
CALL getPositionGridALL();
END;
END IF;
Alternatively:
IF (#CurrUser > 0) THEN
...
END IF;
IF(#CurrUser1 > 0) THEN
...
END IF;
Hope it helps!