How to fix sintax o procedure MySQL with variables? - mysql

I have the following body of procedure, that I can not save cause Mysql sintax error:
BEGIN
DECLARE v_user_id INT;
DECLARE v_order_id INT;
DECLARE v_min_price INT;
UPDATE ordersperformers SET ordersperformers.Status = 1
WHERE EXISTS (
SELECT
MIN(ordersperformers.DeliveryPrice + ordersperformers.Price), ordersperformers.Users_Id,
ordersperformers.Orders_Id
INTO v_min_price, v_user_id, v_order_id
FROM ordersperformers
INNER JOIN
orders ON orders.Id = ordersperformers.Orders_Id WHERE
NOW() >= DATE_SUB(orders.DeliveryDate, INTERVAL 2 HOUR) AND orders.Status = 0 AND ordersperformers.Status = 0
) AND ordersperformers.Orders_Id = v_order_id AND ordersperformers.Users_Id = v_user_id;
END
It tells that problem near INTO:

Reading proposed solution, query can be simplified with JOIN clause and reduced WHERE condition:
UPDATE ordersperformers op
INNER JOIN orders o ON op.Orders_Id = o.Id
SET op.Status = 1
WHERE DATE_SUB(o.DeliveryDate, INTERVAL 2 HOUR) <= NOW()
AND o.Status = 0 AND op.Status = 0

I tested some ways, and have found working sintax, tha fixed my issue:
BEGIN
DECLARE v_user_id INT DEFAULT 0;
DECLARE v_order_id INT DEFAULT 0;
DECLARE v_min_price INT DEFAULT 0;
UPDATE ordersperformers SET ordersperformers.Status = 1
WHERE EXISTS (
SELECT
MIN(ordersperformers.DeliveryPrice + ordersperformers.Price) = #v_min_price, ordersperformers.Users_Id = #v_user_id,
ordersperformers.Orders_Id = #v_order_id
FROM ordersperformers
INNER JOIN
orders ON orders.Id = ordersperformers.Orders_Id WHERE
NOW() >= DATE_SUB(orders.DeliveryDate, INTERVAL 2 HOUR) AND orders.Status = 0 AND ordersperformers.Status = 0
) AND ordersperformers.Orders_Id = v_order_id AND ordersperformers.Users_Id = v_user_id;
END

Related

SQL: return the select value in the stored procedure

I have stored procedure with 3 statements to update sta_fk_col_id in the status table. For test porpuses, I want to return the value in sta_fk_col_id without updating the table. Instead of UPDATE status SET sta_fk_col_id = I tried to do something like SET valido = but without seccuss.
SET valido
CREATE DEFINER=`tpcroot`#`%` PROCEDURE `sp_test_store_procedure`(IN functionId INT, out valido int)
BEGIN
-- statement 1.1
SET valido =
(SELECT CASE WHEN MAX(mon_alertlevel) >= 60 THEN 3 WHEN MAX(mon_alertlevel) < 60
AND MAX(mon_alertlevel) >= 30 THEN 2 ELSE 1 END AS color
FROM monitor INNER JOIN monitor_system ON fk_mon_id = mon_funct_id
WHERE fk_dri_id IN (110))
WHERE sta_fk_dri_id = (110);
-- statement 1.2
SET valido =
(SELECT color FROM ( SELECT MAX(sta_fk_col_id) AS color FROM status WHERE sta_fk_mty_id = 1
AND sta_fk_sys_id = 4
AND sta_fk_dri_id IS NOT NULL) helptable)
WHERE sta_fk_sys_id = 4 AND
sta_fk_mty_id = 1 AND sta_fk_dri_id IS NULL;
-- statement 2
SET valido = (SELECT CASE WHEN MAX(mon_alertlevel) >= 60 THEN 3 WHEN MAX(mon_alertlevel) <60 AND MAX(mon_alertlevel) >= 30 THEN 2 ELSE 1 END AS color
FROM monitor_system INNER JOIN monitor ON fk_mon_id = mon_funct_id AND mon_funct_id = functionId)
WHERE sta_fk_mty_id = 1 AND
sta_fk_sys_id = 4 AND
sta_fk_dri_id IS NULL AND
(SELECT countDrilldown FROM (select Count(*) AS countDrilldown FROM status
WHERE sta_fk_mty_id = 1 AND
sta_fk_sys_id = 4 AND sta_fk_dri_id IS NOT NULL) helptable) = 0;
select #valido;
END
I am calling the stored procedure like this:
CALL sp_test_store_procedure(2315, #returnValue);
select #returnValue;

MySQL Store Procedure Error Code: 1064

I am trying to create stored procedure and getting error:
Error Code: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right
syntax to use near 'DECLARE #LoopCounter INT DEFAULT 0; DECLARE
#MaxId INT DEFAULT 0; DECLARE ' at line 21
DELIMITER $$
USE dollar$$
DROP PROCEDURE IF EXISTS sp_get_products_google_feed$$
CREATE DEFINER=root#localhost PROCEDURE sp_get_products_google_feed()
BEGIN
DROP TABLE IF EXISTS tmp_Product_List;
CREATE TEMPORARY TABLE tmp_Product_List(
SELECT DISTINCT p.products_id AS PID, p.products_model AS ID, pd.products_name AS Title, pd.products_description AS Description,
'' AS Google_product_category, '' AS product_type, p.products_model AS link, p.products_image AS Image_link,
'new' AS Condition1, 'in stock' AS Availability, p.products_price AS Price, '' AS Sale_Price, '' AS Sale_price_effective_date,
p.products_upc AS GTin, p.manufacturers_id, '' AS MPN, '' AS Item_group_id, '' AS Gender, '' AS Age_group, '' AS Color, '' AS Size,
'Free' AS Shipping, '' AS Shipping_Weight
FROM
zc_products_to_categories pc, zc_products p, zc_products_description pd WHERE
pc.categories_id IN
(SELECT DISTINCT mg.sub_category_id AS id FROM tbl_map_google_category_master mg WHERE mg.category_id = 1
UNION
SELECT DISTINCT mg.sub_sub_category_id AS id FROM tbl_map_google_category_master mg WHERE mg.category_id = 1
ORDER BY id) AND
p.products_id = pc.products_id AND
p.products_id = pd.products_id AND
p.products_status = 1 ORDER BY PID);
DECLARE #LoopCounter INT DEFAULT 0;
DECLARE #MaxId INT DEFAULT 0;
DECLARE #GoogleCategoryid INT DEFAULT 0;
SELECT #LoopCounter = MIN(PID), #MaxId = MAX(PID) FROM tmp_Product_List;
WHILE (#LoopCounter IS NOT NULL AND #LoopCounter <= #MaxId)
BEGIN
SELECT #GoogleCategoryid = google_category_id FROM tbl_map_google_category_master
WHERE
category_id = (SELECT MAX(categories_id) FROM zc_products_to_categories WHERE products_id = #LoopCounter) OR
sub_category_id = (SELECT MAX(categories_id) FROM zc_products_to_categories WHERE products_id = #LoopCounter) OR
sub_sub_category_id = (SELECT MAX(categories_id) FROM zc_products_to_categories WHERE products_id = #LoopCounter) LIMIT 0,1;
UPDATE tmp_Product_List SET Google_product_category = #GoogleCategoryid WHERE products_id = #LoopCounter;
SET #LoopCounter = #LoopCounter + 1
IF(##ROWCOUNT = 0 )
BEGIN
SET #LoopCounter = #LoopCounter + 1
CONTINUE
END
END
SELECT * FROM tmp_Product_List;
END$$
DELIMITER ;
But if I remove below code from script, it run successfully. Trying to find error in full script but no luck.
DECLARE #LoopCounter INT DEFAULT 0;
DECLARE #MaxId INT DEFAULT 0;
DECLARE #GoogleCategoryid INT DEFAULT 0;
SELECT #LoopCounter = MIN(PID), #MaxId = MAX(PID) FROM tmp_Product_List;
WHILE (#LoopCounter IS NOT NULL AND #LoopCounter <= #MaxId)
BEGIN
SELECT #GoogleCategoryid = google_category_id FROM tbl_map_google_category_master
WHERE
category_id = (SELECT MAX(categories_id) FROM zc_products_to_categories WHERE products_id = #LoopCounter) OR
sub_category_id = (SELECT MAX(categories_id) FROM zc_products_to_categories WHERE products_id = #LoopCounter) OR
sub_sub_category_id = (SELECT MAX(categories_id) FROM zc_products_to_categories WHERE products_id = #LoopCounter) LIMIT 0,1;
UPDATE tmp_Product_List SET Google_product_category = #GoogleCategoryid WHERE products_id = #LoopCounter;
SET #LoopCounter = #LoopCounter + 1
IF(##ROWCOUNT = 0 )
BEGIN
SET #LoopCounter = #LoopCounter + 1
CONTINUE
END
END
You had a few issues that I've worked through.
The first is the declaring of the variables with an # sign before them, I've removed those.
The second was in the WHILE ... BEGIN ... END. The syntax is WHILE ... DO ... END WHILE.
The third is a missing semi-colon just before the IF(##ROWCOUNT).
The last one that I haven't fixed below is the use of ##ROWCOUNT. ##ROWCOUNT isn't a variable in MySQL. You can find alternatives here
DELIMITER $$
USE dollar$$
DROP PROCEDURE IF EXISTS sp_get_products_google_feed$$
CREATE DEFINER=root#localhost PROCEDURE sp_get_products_google_feed()
BEGIN
DECLARE LoopCounter INT DEFAULT 0;
DECLARE MaxId INT DEFAULT 0;
DECLARE GoogleCategoryid INT DEFAULT 0;
DROP TABLE IF EXISTS tmp_Product_List;
CREATE TEMPORARY TABLE tmp_Product_List(
SELECT DISTINCT p.products_id AS PID, p.products_model AS ID, pd.products_name AS Title, pd.products_description AS Description,
'' AS Google_product_category, '' AS product_type, p.products_model AS link, p.products_image AS Image_link,
'new' AS Condition1, 'in stock' AS Availability, p.products_price AS Price, '' AS Sale_Price, '' AS Sale_price_effective_date,
p.products_upc AS GTin, p.manufacturers_id, '' AS MPN, '' AS Item_group_id, '' AS Gender, '' AS Age_group, '' AS Color, '' AS Size,
'Free' AS Shipping, '' AS Shipping_Weight
FROM
zc_products_to_categories pc, zc_products p, zc_products_description pd WHERE
pc.categories_id IN
(SELECT DISTINCT mg.sub_category_id AS id FROM tbl_map_google_category_master mg WHERE mg.category_id = 1
UNION
SELECT DISTINCT mg.sub_sub_category_id AS id FROM tbl_map_google_category_master mg WHERE mg.category_id = 1
ORDER BY id) AND
p.products_id = pc.products_id AND
p.products_id = pd.products_id AND
p.products_status = 1 ORDER BY PID);
SELECT LoopCounter = MIN(PID), MaxId = MAX(PID) FROM tmp_Product_List;
WHILE (LoopCounter IS NOT NULL AND LoopCounter <= MaxId)
DO
SELECT GoogleCategoryid = google_category_id FROM tbl_map_google_category_master
WHERE
category_id = (SELECT MAX(categories_id) FROM zc_products_to_categories WHERE products_id = LoopCounter) OR
sub_category_id = (SELECT MAX(categories_id) FROM zc_products_to_categories WHERE products_id = LoopCounter) OR
sub_sub_category_id = (SELECT MAX(categories_id) FROM zc_products_to_categories WHERE products_id = LoopCounter) LIMIT 0,1;
UPDATE tmp_Product_List SET Google_product_category = GoogleCategoryid WHERE products_id = LoopCounter;
SET LoopCounter = LoopCounter + 1;
IF(##ROWCOUNT = 0 )
BEGIN
SET LoopCounter = LoopCounter + 1
CONTINUE
END
END WHILE
SELECT * FROM tmp_Product_List;
END$$
DELIMITER ;

How to do a proper SQL recursion?

I'm currently working on a little error-handling issue in the following query:
declare #DayCounter int
declare #rows int
set #DayCounter = -2
set #rows = 0
while #rows = 0
begin
select
coalesce(p.name, case when len(ol.action)>1 then substring(ol.action,1,40)+'<br />'+substring(ol.action,41,80) else ca.code end) as description
, convert(varchar,DateAdd(minute,
15 * ((60 * Datepart(hour, latest_payment_status_change) +
Datepart(Minute, latest_payment_status_change)+
Case When DatePart(second, latest_payment_status_change) < 30
Then 7 Else 8 End) / 15),
DateAdd(day, DateDiff(day, 0, latest_payment_status_change), 0)),126) as date_time
, sum(num_of_persons) as num_tickets
from tick_order o
join tick_orderline ol on ol.order_id=o.id
join (
select olt.id
from tick_orderline_type olt
join tick_case ca on ca.id=olt.case_id
join tick_client tcl on tcl.id = ca.client_id
where tcl.id = 'CLIENT_TEST'
union
select orderline_type_id
from rpt_client_orderline_type rcot
join tick_client tcl on tcl.id = rcot.client_id
where tcl.id = 'CLIENT_TEST'
union
select olt.id
from tick_orderline_type olt
join rpt_client_case rcc on rcc.case_id=olt.case_id
join tick_client cl on cl.id=rcc.client_id
where cl.id = 'CLIENT_TEST'
) olt2 on olt2.id=ol.orderline_type_id
join tick_orderline_type olt on olt.id=ol.orderline_type_id
join tick_case ca on ca.id=olt.case_id
join tick_client cl on cl.id=ca.client_id
join tick_user_case uc on uc.case_id=ca.id
join tick_user u on u.id=uc.user_id
left join tick_promotion_code pc on pc.id=o.promotion_code_id
left join tick_promotion p on p.id=pc.promotion_id
where o.latest_payment_status_change>=dateadd(day,#DayCounter,current_timestamp)
and ((o.latest_payment_status_code = 'ORDER_PAYMENT_OK')
or (o.latest_payment_status_change > dateadd(minute,30,current_timestamp)
and o.latest_payment_status_code = 'ORDER_PAYMENT_WAITING' ))
group by
coalesce(p.name, case when len(ol.action)>1 then substring(ol.action,1,40)+'<br />'+substring(ol.action,41,80) else ca.code end)
, convert(varchar,DateAdd(minute,
15 * ((60 * Datepart(hour, latest_payment_status_change) +
Datepart(Minute, latest_payment_status_change)+
Case When DatePart(second, latest_payment_status_change) < 30
Then 7 Else 8 End) / 15),
DateAdd(day, DateDiff(day, 0, latest_payment_status_change), 0)),126)
order by 1,2
set #DayCounter = #DayCounter - 1;
if ##rowcount <> 0
begin
set #rows = ##rowcount;
print #DayCounter;
end;
end;
The data retrieved is used for a diagram that shows sales per sale-type from the past two days. What I'm trying to achieve now is: When no sales have been made in the past two days (##rowcount = 0), check back a day further each time until data has been found.
The query as it stands now returns something like this (I tried getting the image working, but I somehow am unable to; have a link instead):
https://www.dropbox.com/s/0hculuegrc88c69/SQL_Result.png?dl=0
And it doesn't stop, because for some reason the #rows variable stays 0, despite the query clearly returning rows. Even when using print ##rowcount it returns rows.
SO how do I fix this? Should I use a completely different method?
-Zubaja
It would seem I did not quite understood what my employer meant. He didn't want the error-handling in the SQL, but rather on the website: When no data is found for the past two days, simply show an empty diagram.

SELECT statement from table inside cursor loop force cursor to EXIT

New to MySQL Stored Procedures.
If I uncomment any of the 4 SELECT lines (Below) then the routine EXITS out of the FETCH loop. Do not understand why
-- --------------------------------------------------------------------------------
-- Routine DDL
-- Note: comments before and after the routine body will not be stored by the server
-- --------------------------------------------------------------------------------
DELIMITER $$
CREATE DEFINER=`root`#`localhost` PROCEDURE `UpdateStatusAudit`()
BEGIN
-- Create loop for all $Service records
DECLARE svc_id INT;
DECLARE test INT;
DECLARE svc_name VARCHAR(100);
DECLARE no_more_rows BOOLEAN;
DECLARE up_duration DECIMAL(11,2);
DECLARE down_duration DECIMAL(11,2);
DECLARE maint_duration DECIMAL(11,2);
DECLARE degr_duration DECIMAL(11,2);
DECLARE services_cur CURSOR FOR SELECT service_id,service_name FROM services ORDER BY service_id;
-- Declare 'handlers' for exceptions
DECLARE CONTINUE HANDLER FOR NOT FOUND
SET no_more_rows = TRUE;
OPEN services_cur;
the_loop: LOOP
FETCH services_cur INTO svc_id,svc_name;
IF no_more_rows THEN
CLOSE services_cur;
LEAVE the_loop;
END IF;
SET up_duration = 0;
SET down_duration = 0;
SET maint_duration = 0;
SET degr_duration = 0;
SELECT svc_id;
BEGIN
-- SELECT IFNULL(sum(duration),0) INTO up_duration FROM daily_audit_summary where service_id = svc_id AND status = 'UP' AND Date = current_date - 1 group by date,service_id,status;
-- SELECT IFNULL(sum(duration),0) INTO down_duration FROM daily_audit_summary where service_id = svc_id AND status = 'DOWN' AND Date = current_date - 1 group by date,service_id,status;
-- SELECT IFNULL(sum(duration),0) INTO maint_duration FROM daily_audit_summary where service_id = svc_id AND status = 'MAINT' AND Date = current_date - 1 group by date,service_id,status;
-- SELECT IFNULL(sum(duration),0) INTO degr_duration FROM daily_audit_summary where service_id = svc_id AND status = 'DEGR' AND Date = current_date - 1 group by date,service_id,status;
END;
-- insert into daily_status
INSERT INTO daily_status (date,service_id,time_up,time_down,time_maint,time_degraded) values (current_date-1,svc_id,up_duration,down_duration,maint_duration,degr_duration);
END LOOP the_loop;
END
Did you try assigning the variables like this:
SELECT
up_duration := IFNULL(SUM(duration), 0)
FROM daily_audit_summary
WHERE service_id = svc_id
AND status = 'UP'
AND Date = current_date - 1
GROUP BY
date,
service_id,
status;
?
You could also combine all the assignments into a single SELECT:
SELECT
up_duration := SUM(CASE status WHEN 'UP' THEN duration ELSE 0 END)
down_duration := SUM(CASE status WHEN 'DOWN' THEN duration ELSE 0 END)
maint_duration := SUM(CASE status WHEN 'MAINT' THEN duration ELSE 0 END)
degr_duration := SUM(CASE status WHEN 'DEGR' THEN duration ELSE 0 END)
FROM daily_audit_summary
WHERE service_id = svc_id
AND status = 'UP'
AND Date = current_date - 1
GROUP BY
date,
service_id,
status;
But maybe you could avoid the cursor (and thus the loop) by using a single statement to do all the job:
INSERT INTO daily_status (
date,
service_id,
time_up,
time_down,
time_maint,
time_degraded
)
SELECT
d.Date,
s.service_id,
SUM(CASE das.status WHEN 'UP' THEN das.duration ELSE 0 END),
SUM(CASE das.status WHEN 'DOWN' THEN das.duration ELSE 0 END),
SUM(CASE das.status WHEN 'MAINT' THEN das.duration ELSE 0 END),
SUM(CASE das.status WHEN 'DEGR' THEN das.duration ELSE 0 END)
FROM services s
CROSS JOIN (SELECT CURRENT_DATE - 1 AS Date) AS d
LEFT JOIN daily_audit_summary AS das
ON s.service_id = das.service_id
AND das.Date = d.Date;
I guess that I needed to give a better explanation...
The Code is a Work In Progress and due to requirements, I cannot get rid of the "Services_cur" Cursor.
What I am finding is that when the query for the "Services_Cur" returns say 10 records and within the "the Loop" If I use a SELECT INTO statement from a TABLE such as
"SELECT F1 INTO MyVar from Atable where Afld = somevalue" the LOOP exits as if the "Services Cur" cursor was out of data???
If I issue a "SELECT 1234 INTO MyVar" the Loop works and I get 10 results (As Expected).
I am new to Stored Procedures for MySql and could not find an example of someone doing a series of "SELECT value for table" while within a Loop of FETCHES.
I hope this helps explain the issue better
Thanks for any help.

cursor syntax in Mysql

I followed the example here to a T. But I'm getting syntax errors all over the place. Aside from the fact my code sucks, where is the syntax error?
set #deviation = 30;
set #average = 200000;
DECLARE cur1 CURSOR FOR SELECT distinct subindustry FROM referraldb.report_referral_db_viz_qa;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
open cur1;
read_loop: LOOP
fetch cur1 into sub;
if done then
leave read_loop;
end if;
select #d := max(date) from referraldb.report_referral_db_viz_qa;
select a.subindustry, a.report_time_id, a.dimension_id, a.brand_id, a.referral_source, a.date, a.pre, a.current_test, a.create_dt
from
(select distinct cur.subindustry, cur.report_time_id, cur.dimension_id, cur.brand_id, cur.referral_source, cur.date, cur.pre, cur.current_test, cur.create_dt
from
referraldb.report_referral_db_viz_qa cur
inner join referraldb.report_referral_db_viz_qa prv
on cur.report_time_id = prv.report_time_id
and cur.dimension_id = prv.dimension_id
and cur.brand_id = prv.brand_id
and cur.referral_source = prv.referral_source
and cur.date = date_add(LAST_DAY(DATE_SUB(#d, INTERVAL 1 month)), interval 1 day)
and prv.date = date_add(LAST_DAY(DATE_SUB(#d, INTERVAL 2 month)), interval 1 day)
inner join referraldb.dim_all_dimensions dims
on dims.dimension_id = prv.dimension_id
inner join referraldb.dim_brand brand
on brand.brand_id = prv.brand_id
where
dims.lag = 'immediate'
and dims.measure_type = 'visits'
and prv.subindustry = sub
and prv.report_time_id = 1
and abs((((cur.current_test - prv.current_test)/cur.current_test) * 100)) >= #deviation) a
inner join
(select distinct fact.subindustry, fact.report_time_id, fact.dimension_id, fact.brand_id, fact.referral_source, fact.date, fact.pre, fact.current_test, fact.create_dt
from
referraldb.report_referral_db_viz_qa fact inner join
referraldb.dim_brand brand
on brand.brand_id = fact.brand_id inner join
referraldb.dim_report_time t
on t.report_time_id = fact.report_time_id inner join
referraldb.dim_all_dimensions dims
on dims.dimension_id = fact.dimension_id
where dims.lag = 'Immediate' and dims.measure_type = 'Visits'
and fact.subindustry = sub
and fact.report_time_id = 1 and fact.date > DATE_SUB(#d, INTERVAL 13 month)
group by fact.referral_source, brand.Industry, fact.Subindustry, brand.Brand, dims.Activity, dims.Detail
having avg(current_test) > #average ) b
on a.subindustry = b.subindustry and a.report_time_id = b.report_time_id and a.dimension_id = b.dimension_id and a.brand_id = b.brand_id and a.referral_source= b.referral_source and a.date = b.date and a.pre = b.pre and a.current_test = b.current_test and a.create_dt = b.create_dt
end loop;
close cur1;
How do you execute this block? It should be inside a body of Stored procedure/function (or maybe a trigger). For example,
DELIMITER $$
CREATE PROCEDURE MyProc (//list of parameters)
BEGIN
// your code goes here
END $$
DELIMITER ;
You should add delimiter before and after procedure
DELIMITER $$
//procedure
DELIMITER ;