Stored Procedure WHERE OR HAVING Does Not Work - mysql

In the below procedure,
It gives error ([Err] 1111 - Invalid use of group function) when I use WHERE statements and it gives another error ([Err] 1054 - Unknown column 'roomid' in 'having clause') when I use HAVING statements instead of WHERE, although I have the roomid column defined in the table.
Does anybody have an idea on how can I fix this issue? The code was working perfectly when I tried under another mySQL version I guess.
DELIMITER //
DROP PROCEDURE IF EXISTS `findAVG`//
CREATE DEFINER=`kamer`#`%` PROCEDURE `findAVG`(IN rid INT, startDate DATETIME, OUT Score DOUBLE)
BEGIN
DECLARE finishDate DATETIME;
DECLARE DateIterator DATETIME;
DECLARE avgPrice DOUBLE;
SET avgPrice = 0;
SET Score = 0;
SELECT price into Score
FROM bookings
WHERE roomid = rid
ORDER BY ABS( DATEDIFF( bookings.date, startDate)) LIMIT 1;
IF (Score = 0) THEN
SET DateIterator = startDate;
SET finishDATE = DATE_ADD(startDate, INTERVAL 30 DAY);
WHILE DateIterator <= finishDate DO
SELECT price
INTO avgPrice
FROM prices
WHERE roomid = rid
AND date = DateIterator
ORDER BY DATEDIFF(startDate, prices.timestamp) LIMIT 1;
SET DateIterator = DATE_ADD(DateIterator, INTERVAL 1 DAY);
END WHILE;
SET Score = AVG(avgPrice);
END IF;
UPDATE bookings SET price=Score WHERE roomid= rid AND date=startDate;
END

"Invalid use of group function" mean you've used a column in the group by function that does not appear in the select clause or the inverse.
i.e. :
SELECT A,B,C,COUNT(*) FROM mytable GROUP BY A,B,C
Grouping is done on the 3 firts's columns and the count is done on each line where A,B and C are similar.
For example, if you try to pass "GROUP BY A,B" SQL wont know what to do with C column...
For HAVING problem, it seem to me the HAVING clause is applicated after the select have been done.
So if you're using a column that doesn't appear in the SELECT clause, then it raise an error.

Related

What is the error in it and it is very simple, error is showing in the last 'end' statement. What is the error

There is an error in this code. How can I find it out?
CREATE DEFINER=`root`#`localhost` TRIGGER `check` BEFORE INSERT ON `whatstore` FOR EACH ROW
BEGIN
declare last_insert_time datetime;
declare new_insert_time datetime;
set #last_insert_time=(select insert_time from whatstore order by id desc limit 1);
select datediff(new.insert_time,#last_inserted_time) into new_insert_time;
case
when last_insert_time-new.insert_time>1 then insert into `delete`.table3(time_diff) values(new_inserted_time);
end
END
Your code has a CASE statement, not a CASE expression.
I would advise you to just use IF, but you can adjust your code with END CASE:
begin
declare last_insert_time datetime;
declare new_insert_time datetime;
set #last_insert_time = (select insert_time from whatstore order by id desc limit 1);
select datediff(new.insert_time, #last_inserted_time) into new_insert_time;
case when last_insert_time - new.insert_time > 1
then insert into `delete`.table3 (time_diff)
values (new_inserted_time);
end case;
end;
It seems simpler to write this with no conditional logic:
insert into `delete`.table3 (time_diff)
select w.last_insert_time
from (select insert_time
from whatstore
order by id desc
limit 1
) w
where w.last_insert_time > new.insert_time;

Getting syntax errors when creating function

I have been spending over 2 hours now trying to google my way to the answer.
I am completely new to SQL and MySQL and I have tried to write the following function:
CREATE FUNCTION fp_spinofffactor (id char(8), startdate date)
RETURNS float
BEGIN
DECLARE spinoffFactor float; (ERROR- EXPECTED A ";")
select spinoffFactor = ISNULL(EXP(SUM(LOG(spinoffFactor))),1)
from(
select case when (prev_price- divs) <= 0 THEN 1
else (prev_price- divs)/prev_price end as spinoffFactor
from (select
divs,
fp_v2.fp_prevUnadjPrice(id, ex_date) as prev_price
from (
select sum(fbd.p_divs_pd) as divs,fbd.p_divs_exdate as ex_date
from fp_v2.fp_basic_dividends fbd
where fbd.fsym_id = id
and fbd.p_divs_s_pd=1
and fbd.p_divs_exdate > startdate
group by fbd.p_divs_exdate ) a ) b ) c;
return spinofffactor; ERROR (Return is not valid at this position)
END ERROR (END IS NOT VALID AT THIS position)
But I get multiple syntax errors. I have written the errors where I get them.
I have a hard time finding information about the syntax rules of MySQL and the workbench.
Can anyone help ?
You need to provide delimiter in MySql workbench to tell where your code begins and ends.
Assuming your syntax is correct, you can write as below.
DELIMITER $$
CREATE FUNCTION fp_spinofffactor (id char(8), startdate date)
RETURNS float
BEGIN
DECLARE spinoffFactor float;
select spinoffFactor = ISNULL(EXP(SUM(LOG(spinoffFactor))),1)
from(
select case when (prev_price- divs) <= 0 THEN 1
else (prev_price- divs)/prev_price end as spinoffFactor
from (select
divs,
fp_v2.fp_prevUnadjPrice(id, ex_date) as prev_price
from (
select sum(fbd.p_divs_pd) as divs,fbd.p_divs_exdate as ex_date
from fp_v2.fp_basic_dividends fbd
where fbd.fsym_id = id
and fbd.p_divs_s_pd=1
and fbd.p_divs_exdate > startdate
group by fbd.p_divs_exdate ) a ) b ) c;
return spinofffactor;
END$$
DELIMITER ;
You can also, run this from MySQL command prompt and it should work.

Create a loop based on date Mysql

I have a query :
insert into fookoo_business
select stat_date, sum(spend), sum(revenue)
from hooloo_business;
that i want to run for each date from '2017-01-20' until yesterday (it means the query will run 434 times if we're at 01/04/2018), for each date separately
(in a loop).
how can i create a loop in Mysql to do it for me?
I have tried:
creating procedure for the query select #stat_date, sum(spend), sum(revenue)
I called 'query'
then :
CREATE PROCEDURE loop_procedure()
BEGIN
SET #stat_date='2018-03-20';
CALL 'query';
REPEAT
SET #stat_date = #stat_date + INTERVAL 1 DAY;
UNTIL #stat_date = CURDATE() END REPEAT;
END
eventually i've used the following logic within a stored procedure to fetch the data:
PROCEDURE `x_monitoring_loop`()
BEGIN
DECLARE i INT;
DECLARE len INT;
SET len = 434;
SET i = 0;
WHILE (i < len) DO
SET #stat_date= CURDATE()-INTERVAL 1 DAY;
SET #stat_date= #stat_date- INTERVAL i DAY;
Insert query;
SET i = i +1;
END WHILE;
This way the query ran 434 times for each day, beginning at current date - 1 day.
I do not know why you want to use a procedure,I think we can just use a query sql to do it:
INSERT INTO fookoo_business
SELECT stat_date, SUM(spend), SUM(revenue)
FROM hooloo_business
WHERE stat_date BETWEEN STR_TO_DATE('2017-01-02', '%Y-%m-%d') -- start date
AND DATE_SUB(NOW(), INTERVAL 1 DAY) -- end date
GROUP BY stat_date;

MySql nested Store Procedure Call

I have 2 stored Procedures in MySQL. I want to call one from the other but I need some help with the syntax
Here is Procedure 1 FindPreviousDate
DELIMITER $$ CREATE PROCEDURE `FindPreviousDate`(IN eventdate DATETIME, IN lookbackDays INT, IN symbol VARCHAR(20))
BEGIN
SELECT *
FROM Price a
WHERE a.eventDate between (eventDate - interval lookbackDays day) and (eventdate - interval 1 day) and a.symbol = symbol
ORDER BY a.eventDate DESC
LIMIT 1;
END
Here is Procedure 2 FindCloseEvent
CREATE PROCEDURE `FindCloseEvent`(IN startdate DATETIME, IN enddate DATETIME,IN symbol VARCHAR(20), IN cutoff DOUBLE)
BEGIN
SELECT *
FROM Price a
WHERE a.eventDate between startdate and enddate and
(SELECT COUNT(*) from Price b where b.eventDate = a.eventDate and b.closePrice < cutoff and a.symbol = b.symbol and
(SELECT COUNT(*) from Price c where c.eventDate = (b.eventDate - interval 1 day) and c.closePrice >= cutoff and b.symbol = c.symbol));
END
I want to replace this code in Procedure 2 with the result of Procedure 1
(b.eventDate - interval 1 day)
I need help getting the syntax right. I'm not even sure if mySql allows for what I'm asking.
Thanks!
On procedures you can use OUT variables, which get filled and are available outside the procedure.
OR
Since a MySQL procedure does not return a value. You'll need a stored function to achieve this.
use the example given into below link to call a function1 from your procedure2
http://www.java2s.com/Code/SQL/Procedure-Function/Callanotherfunction.htm
you can even store the result of function1 into some variable of procedure2 and use it later in query

Select in MySQL stored procedure not returning values

I have a stored procedure, shown below, which I created to add dollar sales to a table (WeeklySales) which currently stores only unit sales. The cursor operates on on the WeeklySales table. The pricing data is stored in the Pricing table. The Pricing table actually contains changes in prices. The effective date for a price change is stored in Pricing.effectiveDate, so I have to find the pricing which was effective for the week in which the unit was sold (which is stored in WeeklySales.weekStart).
The problem I'm having is that the first select after the IF doesn't return anything. I've confirmed that this select does return a value when I run it outside of the procedure using the values which it would be called with inside the procedure. I'm not sure what's wrong here, but I'm guessing maybe this has to do with the fact that the this select is operating on a table which is different from the cursor? Anyone know? Is there a better way to do this?
DELIMITER //
CREATE PROCEDURE `createWeeklyPricing` (IN startDate DATE, IN endDate DATE)
BEGIN
--
-- Populate the proceeds column using the Pricing table
DECLARE product VARCHAR(255);
DECLARE weekStart DATE;
DECLARE units, done INT;
DECLARE proceeds DECIMAL(6,2);
DECLARE effectiveDate DATE;
DECLARE currentRow CURSOR FOR SELECT `weekStart`, `product`, `units` FROM `WeeklySales` WHERE `weekStart` >= startDate AND `weekStart` <= endDate;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN currentRow;
SET done = 0;
WHILE done = 0 DO
FETCH currentRow INTO weekStart, product, units;
IF done = 0 THEN
SELECT MAX(`effectiveDate`) FROM `Pricing` WHERE `effectiveDate` <= weekStart AND `product` = product INTO effectiveDate;
SELECT `proceeds` FROM `Pricing` WHERE `effectiveDate` = effectiveDate AND `product` = product INTO proceeds;
UPDATE `WeeklySales` SET `proceeds` = units * proceeds WHERE `weekStart` = weekStart AND `product` = product;
END IF;
END WHILE;
CLOSE currentRow;
END//
echo (select) weekstart before the if statement...
If it returns null change the select FROM WeeklySales WHERE weekStart between startDate AND endDate
you need to use the INTO before FROM and variable needs '#' sign
change it to
SELECT MAX(`effectiveDate`) INTO #effectiveDate FROM `Pricing` WHERE `effectiveDate` <= weekStart AND `product` = product ;
hope this helps
This is because your variable name is overwriting your column name:
You have a variable named 'effectiveDate'
You have a column named 'effectiveDate'
SELECT MAX(`effectiveDate`) ...
Is MAX-ing the variable effectiveDate, not the column
Try naming the variable maxEffectiveDate
Beware that variables are case insensitive. This happened to me when i tried to select column IsBackUp into variable isBackUp (notice the i).