MySQL 5.1 Stored Procedure Error - Declaring Variable - mysql

Running into an error when trying to crate a stored procedure in MySQL (5.1).
Whenever I try and run this SQL script, I am presented with:
Error 1064 (42000) At line 3: You have an error in your SQL syntax.
Near 'DECLARE checkExists INT; SET checkExists = 0; SELECT count(*) INTO c' at line 29
From what I understand, declaring a variable this way should be acceptable.
I have included the SQL script below.
DELIMITER //
CREATE PROCEDURE add_movie(
IN movieTitle VARCHAR(100),
IN movieYear INT,
IN movieDirector VARCHAR(100),
IN movieBannerURL VARCHAR(100),
IN movieTrailerURL VARCHAR(100),
IN starFirstName VARCHAR(50),
IN starLastName VARCHAR(50),
IN starDateOfBirth DATE,
IN starPhotoURL VARCHAR(200),
IN genreName VARCHAR(32),
OUT movieAdded INT,
OUT starAdded INT,
OUT genreAdded INT,
OUT movieStarLinkAdded INT,
OUT movieGenreLinkAdded INT)
LANGUAGE SQL
NOT DETERMINISTIC
SQL SECURITY INVOKER
COMMENT 'Adds Movie, Star, Genre and respective links to DB if they do not exist'
BEGIN
SET movieAdded = 0;
SET starAdded = 0;
SET genreAdded = 0;
SET movieStarLinkAdded = 0;
SET movieGenreLinkAdded = 0;
DECLARE checkExists INT;
SET checkExists = 0;
SELECT count(*) INTO checkExists FROM movies m WHERE m.title = movieTitle;
IF(checkExists > 0) THEN
INSERT INTO movies(title, year, director, banner_url, trailer_url)
VALUES (movieTitle, movieYear, movieDirector, movieBannerURL, movieTrailerURL);
SET movieAdded = 1;
END IF;
SET checkExists = 0;
SELECT count(*) INTO checkExists FROM stars s WHERE s.first_name = starFirstName AND s.last_name = starLastName;
IF(checkExists > 0) THEN
INSERT INTO stars(first_name, last_name, dob, photo_url)
VALUES (starFirstName, starLastName, starDateOfBirth, starPhotoURL);
SET starAdded = 1;
END IF;
SET checkExists = 0;
SELECT count(*) INTO checkExists FROM genres g WHERE g.name = genreName;
IF(checkExists > 0) THEN
INSERT INTO genres(name)
VALUES (genreName);
SET genreAdded = 1;
END IF;
SET checkExists = 0;
SELECT count(*) INTO checkExists FROM stars_in_movies sm, stars s, movies m
WHERE m.title = movieTitle AND s.first_name = starFirstName
AND s.last_name = starLastName AND sm.star_id = s.id AND sm.movie_id = m.id;
IF(checkExists > 0) THEN
INSERT INTO stars_in_movies(star_id, movie_id)
VALUES(
SELECT s.id, m.id FROM stars s, movies m WHERE s.first_name = starFirstName
AND s.last_name = starLastName AND m.title = movieTitle);
SET movieStarLinkAdded = 1;
END IF;
SET checkExists = 0;
SELECT count(*) INTO checkExists FROM genres_in_movies gm, genres g, movies m
WHERE m.title = movieTitle AND genre.name = genreName
AND gm.movie_id = m.id AND gm.genre_id = g.id;
IF(checkExists > 0) THEN
INSERT INTO genres_in_movies(genre_id, movie_id)
VALUES(
SELECT g.id, m.id FROM genres g, movies m
WHERE g.name = genreName AND m.title = movieTitle);
SET movieGenreLinkAdded = 1;
END IF;
END //
DELIMITER ;
If someone could help me understand what I am doing incorrectly here, I would greatly appreciate it. Thank you.

Move all DECLARE statements to the start of a BEGIN .. END block, next to BEGIN.
See documentation: https://dev.mysql.com/doc/refman/5.6/en/declare.html
DECLARE is permitted only inside a BEGIN ... END compound statement and must be at its start, before any other statements.

Related

how save a selected record into a variable?

I'm in a problem with the following query ..
After inserting in the table rtoxvta record by record, I need before the end of the loop eliminate the record of the vta table prevously selected.
For that i declare a new variable and assign it the vta id .. but where do I do it?
DROP PROCEDURE IF EXISTS ROWPERROW;
DELIMITER ;;
CREATE PROCEDURE ROWPERROW()
BEGIN
DECLARE n INT DEFAULT 0;
DECLARE indexx INT DEFAULT 0;
#DECLARE aux INT DEFAULT 0;
SELECT COUNT(*) FROM rto INTO n;
SET n = n +1;
SET indexx=0;
WHILE indexx<n DO
INSERT INTO rtoxvta (fecharto, importerto, fechavta, importevta)
SELECT r.fecha, r.importe, v.fecha, v.importe
FROM vta v
left outer join rto r
ON r.id = indexx
WHERE v.fecha >= r.fecha
AND (
(v.importe = r.importe) OR
(v.importe + 2 = r.importe) OR
(v.importe + 1 = r.importe) OR
(v.importe - 1 = r.importe) OR
(v.importe - 2 = r.importe))
LIMIT 1;
SET indexx = indexx + 1;
#DELETE FROM vta WHERE id = aux;
END WHILE;
End;
;;
CALL ROWPERROW();
You'll have to do it as two steps. First get the ID of the record you're going to insert into a variable, then insert that record. Then you can delete the record.
WHILE indexx<n DO
SELECT v.id, r.id INTO #v_id, #r_id
FROM vta v
join rto r
ON r.id = indexx
WHERE v.fecha >= r.fecha
AND r.importe BETWEEN v.importe - 2 AND v.importe + 2
LIMIT 1;
INSERT INTO rtoxvta (fecharto, importerto, fechavta, importevta)
SELECT r.fecha, r.importe, v.fecha, v.importe
FROM vta v
CROSS JOIN rto r
WHERE v.id = #v_id AND r.id = #r_id;
SET indexx = indexx + 1;
DELETE FROM vta WHERE id = #v_id;
END WHILE;
Also, if you're using a column from rto in the WHERE clause, you should use INNER JOIN rather than LEFT OUTER JOIN. The WHERE condition will not match any rows that don't have a match in rto, so there's no point in using an outer join.

Adding procedure in database

I'm trying to create a procedure that adds data into two tables at the same time but using mySQL, but I don't have much experience using if/else statement in database so could someone tell me how I can fix my code
Here the Attributes:
Customer information: ID,Name, Address, Telephone.
Staff information: ID, Name, Phone
Camera/Len Type: ID,Name
Camera: ID, typeID, Model, Status, Color, Hiring Price (per day), Paying Price (in case of loss).
Len: ID, TypeID, Model, Status, Hiring Price (per day), Paying Price (in case of loss).
Order orderID, customerID, employeeID, hireDate, returnDate
OrderDetail: orderID, cameraID, lenID, cameraQuantity, lenQuantity, Status(paid/not paid), pStatus(Lost/Ok)
Here's the Procedure code:
DELIMITER $$
Create Procedure addOrder(IN cust_id int, IN camera_id int, IN len_id int,
IN emp_id int, IN c_quantity int,IN l_quantity int,
IN status char(30), IN p_Status char(30), IN hire_date date, IN return_date
date)
begin
Declare order_id int;
Declare hireTime int;
Declare totalC int;
Declare totalL int;
Declare totalP int;
Select order_id = max(orderID) from orders;
if orderID is null then set order_id = 1;
Set hireTime = DATEDILL(hire_date, return_date);
if hire_date == return_date then set hireTime = 1;
if p_Status = "Lost" then set
select totalC = hireTime*c_quantity*hPrice + pPrice from Camera as C
inner join orderDetail as OD on C.camID = OD.camera_id inner join Orders
as O on O.orderID = OD.order_id;
select totalL = hireTime*l_quantity*hPrice + pPrice from Lens as L
inner join orderDetail as OD on L.lenID = OD.len_id inner join Orders as
O on O.orderID = OD.order_id;
Set totalP = totalL + totalC;
else set
select totalC = hireTime*c_quantity*hPrice + pPrice from Camera as C
inner join orderDetail as OD on C.camID = OD.camera_id inner join Orders
as O on O.orderID = OD.order_id;
select totalL = hireTime*l_quantity*hPrice + pPrice from Lens as L
inner join orderDetail as OD on L.lenID = OD.len_id inner join Orders as
O on O.orderID = OD.order_id;
Set totalP = totalL + totalC;
end if;
insert into Orders(custID, empID, hireDate, returnDate)
values (cust_id, emp_id,hire_date, return_date);
insert into orderDetail(orderID, cameraID, lenID, totalPrice, camQuantity,
lenQuantity, status, pStatus) values (order_id,camera_id, len_id, totalP,
c_quantity, l_quantity, status, p_Status);
end $$
DELIMITER
I think u need to use view table to add all tables after that use stored procedure. And I give you and example I think u can figure out.
CREATE PROCEDURE [dbo].[sp_CMIDByID] #UID INT, #TID INT
AS
BEGIN
DECLARE #CMID INT
IF(#TID IS NULL AND #UID IS NOT NULL)
BEGIN
SELECT #TID = TID, #CMID = CMID FROM tbl_U WHERE UID = #UID
END
IF (#CMID IS NULL AND #TID IS NOT NULL)
BEGIN
SELECT #CMID = CMID FROM tbl_T WHERE TID = #TID
END
SELECT #CMID
END

MySQL summary function on N-th row

I try to create a function, that returns the summary on the n-th row, where n defined by the order a query result.
This is what I have:
CREATE DEFINER=`root`#`localhost` FUNCTION `fn_inventory_stock_on_note`( fIngredient int, fInventory int, fNote int ) RETURNS float
DETERMINISTIC
BEGIN
DECLARE tStock float;
DECLARE tNoteRow int;
DECLARE tDummy int;
DECLARE rStock float;
DECLARE rRow int;
SET tNoteRow = 0;
SET #rRow := 0;
SELECT #rRow := #rRow + 1, b.ID
INTO tNoteRow, tDummy
FROM fn_inventory_book b
LEFT JOIN fn_inventory_book_in bi ON b.id = bi.bookid
LEFT JOIN fn_inventory_book_out bo ON b.id = bo.bookid
LEFT JOIN fn_dict_transactions t ON b.transactionid = t.id
WHERE b.inventoryid = fInventory
AND ( bi.ingredientid = fIngredient OR bo.ingredientid = fIngredient )
HAVING b.ID = fNote
ORDER BY b.date ASC, t.direction ASC;
SET #rRow := 0;
SET #rStock := 0;
SELECT rStock INTO tStock
FROM ( SELECT #rRow := #rRow + 1 as rRow, #rStock := #rStock + ifnull( if( bi.id is not null, bi.quantity, bo.quantity ), 0 ) * t.direction as rStock
FROM fn_inventory_book b
LEFT JOIN fn_inventory_book_in bi ON b.id = bi.bookid
LEFT JOIN fn_inventory_book_out bo ON b.id = bo.bookid
LEFT JOIN fn_dict_transactions t ON b.transactionid = t.id
WHERE b.inventoryid = fInventory
AND ( bi.ingredientid = fIngredient OR bo.ingredientid = fIngredient )
ORDER BY b.date ASC, t.direction ASC ) as q
WHERE rRow = tNoteRow;
RETURN tStock;
END
Where fIngredient and fInventory is an id for the query's filter, and fNote is a PK from the fn_inventory_book table.
The first select gets the required row's number in the order, which works fine.
My problem is in the second query, which in the subquery creates a table with the same filter and order like the first select, with the same row numbers, and the cumulative quantity of each row. And in the main query I filter that with the row number I got in the first select.
At least this is what should happen. But instead of that, when I run the function like:
select fn_inventory_stock_on_note( 1545, 18, 124167 ) as stock from dual;
It returns NULL, but if I run the second query separately with the same params, I get an amount back.
But not the right number because if I only run the second query's subquery, the row numbers aren't in order (1,2,3,6,7,4,5,8,9,10 instead of 1,2,3,..,10).
What am I doing wrong? Any help will be appreciated.
Feel free to ask if my description isn't clear.
I figured out a solution for my problem, but if anyone has a better one, please share it, because I don't think mine is the right one, although it does the job.
DROP function IF EXISTS `fn_inventory_stock_on_note`;
DELIMITER $$
CREATE DEFINER=`root`#`localhost` FUNCTION `fn_inventory_stock_on_note`( fIngredient int, fInventory int, fNote int, fItem int ) RETURNS float
DETERMINISTIC
BEGIN
DECLARE tStock float;
DECLARE tNoteRow int;
DECLARE rStock float;
DECLARE rRow int;
SET #rRow := 0;
DROP TEMPORARY TABLE IF EXISTS stock_temp;
CREATE TEMPORARY TABLE stock_temp ( num int, BookID int, ItemID int, qty float );
INSERT INTO stock_temp ( SELECT #rRow := #rRow + 1 as num, q.*
FROM ( SELECT b.id as BookID, if( bi.id is not null, bi.id, bo.id ) as ItemID,
ifnull( if( bi.id is not null, bi.quantity, bo.quantity ), 0 ) * t.direction as qty
FROM fn_inventory_book b
LEFT JOIN fn_inventory_book_in bi ON b.id = bi.bookid
LEFT JOIN fn_inventory_book_out bo ON b.id = bo.bookid
LEFT JOIN fn_dict_transactions t ON b.transactionid = t.id
WHERE b.inventoryid = fInventory
AND ( bi.ingredientid = fIngredient OR bo.ingredientid = fIngredient )
ORDER BY b.date ASC, t.direction ASC ) as q );
SELECT num INTO tNoteRow
FROM stock_temp st
WHERE st.BookID = fNote
AND st.ItemID = fItem;
SELECT sum( st.qty ) INTO tStock
FROM stock_temp st
WHERE st.num <= tNoteRow;
RETURN tStock;
END$$
DELIMITER ;

MySQL incrementing variable in stored procedure

So I have a routine that does (pseudo-code):
$rows = SELECT DISTINCT a, b FROM t1;
foreach($rows as $row) {
SET #i = 0;
UPDATE t1 SET c_index = #i := (#i+1)
WHERE a = $row[a] and b = $row[b] ORDER BY c DESC;
}
The point is to number a subset of rows by the way they are sorted. Works fine, but this is update runs thousands of times so is pretty slow. To speed it up I want to put it in a stored procedure.
BEGIN
DECLARE done INT DEFAULT 0;
DECLARE vA, vB, i INT;
DECLARE cur1 CURSOR FOR
SELECT DISTINCT a, b
FROM t1 WHERE ...;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN cur1;
WHILE done = 0 DO
FETCH cur1 INTO vA, vB;
IF done = 0 THEN
SET i=0;
UPDATE t1
SET c_index = i:= (i+1)
WHERE a = vA AND b = vB
ORDER BY c DESC;
END IF;
END WHILE;
CLOSE cur1;
END
However, when creating the above procedure MySQL says there is a syntax error at "i := ...". If I use a session variable for 'i' it works (#i). Using a session variable in a stored procedure is not very elegant. How can the above stored procedure be fixed without using a session variable for 'i'?
UPDATED: Since MySQL cursors are not updatable (read-only) there is no much sense of using one in your case. Almost everything you can possibly think of can be expressed just by pure UPDATE statement(s).
If (a, b, c) are unique you can do it this way
UPDATE table1 t JOIN
(
SELECT a, b, c,
(
SELECT 1 + COUNT(*)
FROM table1
WHERE a = t.a
AND b = t.b
AND c > t.c
) rnum
FROM table1 t
) s
ON t.a = s.a
AND t.b = s.b
AND t.c = s.c
SET t.c_index = s.rnum
Here is SQLFiddle demo
or if you happen to have some sort of id (e.g. auto_increment column) then
UPDATE table1 t JOIN
(
SELECT id,
(
SELECT 1 + COUNT(*)
FROM table1
WHERE a = t.a
AND b = t.b
AND c > t.c
) rnum
FROM table1 t
) s
ON t.id = s.id
SET t.c_index = s.rnum
Here is SQLFiddle demo

mysql stored procedure

I have created a following stored procedure to insert rows in the table panel_user:
CREATE PROCEDURE panel_users()
BEGIN
DECLARE i INTEGER;
DECLARE user_id BIGINT(20);
DECLARE panel_id BIGINT(20);
DECLARE wt DECIMAL(10,6);
DECLARE level DECIMAL(6,2);
DECLARE total INTEGER;
SET i=1;
SELECT COUNT(*) INTO total FROM smartmeter_usage.users_reporting;
WHILE i<=total DO
SELECT u.userId INTO user_id, p.panelId INTO panel_id, ur.usage_percent INTO level, ipr.wt_base INTO wt
FROM mondrainusage.user_d u
INNER JOIN smartmeter_usage.imei_phone_reporting ipr ON u.imeiNumber = ipr.IMEI
INNER JOIN smartmeter_usage.users_reporting ur ON ur.mobile_number = ipr.mobile_number
INNER JOIN smartmeter_usage.panel pn ON pn.panel_id = ur.panel_id
INNER JOIN mondrainusage.panel p ON p.panelName = pn.panel_name
WHERE u.userId = i;
INSERT INTO mondrainusage.panel_user (panelId, userId, userWeight, usageLevel) VALUES(panel_id, user_id, wt, level);
SET i = i+1;
END WHILE
END
I am getting following error:
Undeclared variable: p
I am not getting what is wrong here in my query. Is there a way out of it?
EDIT:
k I got the solution for the above problem. here is the solution:
CREATE PROCEDURE panel_users()
BEGIN
DECLARE i INTEGER;
DECLARE user_id BIGINT(20);
DECLARE panel_id BIGINT(20);
DECLARE wt DECIMAL(10,6);
DECLARE level DECIMAL(6,2);
DECLARE total INTEGER;
SET i=1;
SELECT COUNT(*) INTO total FROM smartmeter_usage.users_reporting;
WHILE i<=total DO
SELECT u.userId, p.panelId, ur.usage_percent, ipr.wt_base INTO user_id, panel_id, level, wt
FROM mondrainusage.user_d u
INNER JOIN smartmeter_usage.imei_phone_reporting ipr ON u.imeiNumber = ipr.IMEI
INNER JOIN smartmeter_usage.users_reporting ur ON ur.mobile_number = ipr.mobile_number
INNER JOIN smartmeter_usage.panel pn ON pn.panel_id = ur.panel_id
INNER JOIN mondrainusage.panel p ON p.panelName = pn.panel_name
WHERE u.userId = i;
INSERT INTO mondrainusage.panel_user (panelId, userId, userWeight, usageLevel) VALUES(panel_id, user_id, wt, level);
SET i = i+1;
END WHILE
END
Bit now it is giving me syntax error near 'END' at line 21.
Why is this so?
EDIT:
Got the solution:
END WHILE;
Here is a solution that worked.
CREATE PROCEDURE panel_users()
BEGIN
DECLARE i INTEGER;
DECLARE user_id BIGINT(20);
DECLARE panel_id BIGINT(20);
DECLARE wt DECIMAL(10,6);
DECLARE level DECIMAL(6,2);
DECLARE total INTEGER;
SET i=1;
SELECT COUNT(*) INTO total FROM smartmeter_usage.users_reporting;
WHILE i<=total DO
SELECT u.userId, p.panelId, ur.usage_percent, ipr.wt_base INTO user_id, panel_id, level, wt
FROM mondrainusage.user_d u
INNER JOIN smartmeter_usage.imei_phone_reporting ipr ON u.imeiNumber = ipr.IMEI
INNER JOIN smartmeter_usage.users_reporting ur ON ur.mobile_number = ipr.mobile_number
INNER JOIN smartmeter_usage.panel pn ON pn.panel_id = ur.panel_id
INNER JOIN mondrainusage.panel p ON p.panelName = pn.panel_name
WHERE u.userId = i;
INSERT INTO mondrainusage.panel_user (panelId, userId, userWeight, usageLevel) VALUES(panel_id, user_id, wt, level);
SET i = i+1;
END WHILE;
END