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
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;
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 ;
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.
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.
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 ;