While Loops in MYSQL/PHPMyAdmin with Dates - mysql

I am trying to pull a sum from my data that is comparing one month to the next. The below code provides what I need to compare two months but I need to run this over 4 years.
SELECT as_of_date,
Sum(case when `as_of_date` = '2014-02-01' AND disclosure_number IN(
SELECT disclosure_number
FROM `gnma_cohort`
WHERE obp BETWEEN '125001' AND '150000' AND in_the_money BETWEEN '0'
AND '49.999' AND `as_of_date` = '2014-01-01') THEN 1 END) AS '2014-
02-01'
FROM `gnma_cohort`
I am new to MySQL but from what I have read it seems a While loop would be my best option. Below is my attempt at creating the loop but I keep getting errors on my delimiter, is this not the correct format for mysql in PHPMYAdmin? I also do not have the standard ; delimiter in my code that I have seen other examples use, but I never use the ; delimiter in phpmyadmin. Any advice on how to fix my code would be greatly appreciated, thank you!
DELIMITER $$
DROP PROCEDURE IF EXISTS itmdates$$
CREATE PROCEDURE itmdates()
BEGIN
DECLARE startdate DATE
WHILE startdate < '2017-10-01' DO
SELECT as_of_date,
Sum(case when `as_of_date` = startdate AND disclosure_number
IN(
SELECT disclosure_number
FROM `gnma_cohort`
WHERE obp BETWEEN '125001' AND '150000' AND in_the_money
BETWEEN '0' AND '49.999' AND `as_of_date` =
DATE_SUB(startdate, INTERVAL 1 MONTH) THEN 1 END) AS
'startdate'
SET startdate = DATE_ADD(startdate, INTERVAL 1 MONTH)
END WHILE
END$$

Related

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;

SQL: DATE_ADD(date,INTERVAL expr type) skip weekends

I'm currently using DATE_ADD(date,INTERVAL expr type) to set a due date as a trigger in a mySQL Database.
What I'm wanting to know is if it is possible to skip weekends (Saturday, Sunday) as part of the trigger.
You'd have to create an own function for doing that. You can look how to do that in this answer, for example (just use function instead of procedure). As for how to write such a function, here's a working algorithm. The code is quite straightforward: it loops through days and skips weekends.
CREATE FUNCTION `DAYSADDNOWK`(addDate DATE, numDays INT) RETURNS date
BEGIN
IF (WEEKDAY(addDate)=5) THEN
SET addDate=DATE_ADD(addDate, INTERVAL 1 DAY);
END IF;
IF (WEEKDAY(addDate)=6) THEN
SET addDate=DATE_ADD(addDate, INTERVAL 1 DAY);
END IF;
WHILE numDays>0 DO
SET addDate=DATE_ADD(addDate, INTERVAL 1 DAY);
IF (WEEKDAY(addDate)=5) THEN
SET addDate=DATE_ADD(addDate, INTERVAL 1 DAY);
END IF;
IF (WEEKDAY(addDate)=6) THEN
SET addDate=DATE_ADD(addDate, INTERVAL 1 DAY);
END IF;
SET numDays=numDays-1;
END WHILE;
RETURN addDate;
END
Currently SELECT DAYSADDNOWK(CURDATE(), 5) yields 2016-03-07, which is correct.
Of course you only can use it with days, so no arbitrary interval, but your question mentioned date datatype, and I don't quite see how one could add a month not counting working days.
This function simply creates a list of dates starting at the date given in the arguments, and then figures out which date is x number of days (the interval) out while disregarding days 1 and 7 (which are Sunday and Saturday respectively on SQL Server).
CREATE FUNCTION [dbo].[udf_days_add_no_wknd]
(
#start_date date
, #interval int
)
RETURNS date
AS
BEGIN
declare #answer date
; with dates as
(
select #start_date as date_val
union all
select dateadd(d, 1, date_val) as date_val
from dates
where date_val < dateadd(d, #interval * 10, #start_date)
)
, final as
(
select top 1 lead(ld.date_val, #interval, NULL) over (order by ld.date_val asc) as new_date_val
from dates as ld
where 1=1
and datepart(dw, ld.date_val) not in (1,7) --eliminating weekends
)
select #answer = (select new_date_val from final)
return #answer
END
It is worth nothing that this solution is dependent on having SQL Server 2012 or later, considering the use of the lead() function.

How to get the number of business days using mysql

I have to find the number of business days using mysql.I am using this query but this is not giving me the correct result
SELECT ((DATEDIFF('2015-05-31', '2015-05-01')) -((WEEK('2015-05-31') - WEEK('2015-05-01')) * 2) -
(case when weekday('2015-05-31') = 6 then 1 else 0 end) - (case when weekday('2015-05-01') = 5 then 1 else 0 end))
as DifD ;
It is giving 19 as output where number of business days should be 20
Somebody please help
Try this!
SET #i=-1;
SELECT SUM(CASE WHEN(WEEKDAY(ADDDATE('2015-05-01', INTERVAL #i:=#i+1 DAY))) < 5 THEN 1 ELSE 0 END) AS `business_days`
FROM `table`
WHERE #i < DATEDIFF('2015-05-31', '2015-05-01');
Hope this answer helps!
drop procedure COUNTWEEKDAYS;
DELIMITER $$
CREATE PROCEDURE COUNTWEEKDAYS (FROMDATE TIMESTAMP, TODATE TIMESTAMP)
begin
declare NOOFWEEKDAYS INTEGER;
set NoOfWeekDays = (datediff(todate, fromdate) + 1)
-((timestampdiff(week, FROMDATE , TODATE) * 2))
-weekday(fromdate)%4
-weekday(todate)%4;
select NOOFWEEKDAYS;
end$$

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

Whats wrong with this short procedure (MySQL)

Im trying to make a procedure, which will be checking if user is already logged (he got a session, and im checking if his last action was over 15 minutes ago). My procedure looks like this:
CREATE PROCEDURE `isLogged`(in p_sessid VARCHAR(32), out res INT(1))
BEGIN
DECLARE v_customer_id INT(9);
DECLARE v_date DATE;
SELECT customer_id INTO v_customer_id FROM Sessions WHERE sessid=p_sessid;
SELECT expiry_date INTO v_date FROM Sessions WHERE sessid=p_sessid;
SET res=3;
IF v_customer_id > 0 THEN
IF UNIX_TIMESTAMP(NOW()) > UNIX_TIMESTAMP(v_date) THEN
DELETE FROM Sessions WHERE sessid=p_sessid;
SET res=1;
ELSE
UPDATE Sessions SET expiry_date=DATE_ADD(NOW(), INTERVAL 15 MINUTE) WHERE customer_id=v_customer_id;
SET res=0;
END IF;
END IF;
END
Can anyone tell, why it always return 1, what means that user is not logged anymore? I were checking manually expression UNIX_TIMESTAMP(NOW()) > UNIX_TIMESTAMP(v_date), and it gives me 0 in response, so? Whats going on?
Thanks in advance,
Marcin
The first IF statement should read like this:
UNIX_TIMESTAMP(NOW()) > UNIX_TIMESTAMP(DATE_ADD(v_date, INTERVAL 15 MINUTE))
or else NOW will always be greater than the last login date.
You may rewrite/optimize your procedure to function. For example -
CREATE FUNCTION `isLogged`(IN p_sessid VARCHAR(32))
RETURNS INT
BEGIN
DELETE FROM Sessions WHERE sessid = p_sessid AND v_date <= NOW() - INTERVAL 15 MINUTE;
IF ROW_COUNT() > 0 THEN -- check how many rows were deleted
RETURN 1;
ELSE
UPDATE Sessions SET expiry_date = NOW() + INTERVAL 15 MINUTE WHERE customer_id = v_customer_id;
IF ROW_COUNT() > 0 THEN -- check how many rows were updated
RETURN 0;
END IF;
END IF;
RETURN 3;
END
Also, you can try to debug your code to understand the error.
Omg, that was very stupid.
There was a type mismatch. v_date type was a DATE, and this is just a day! Like 2011-12-14.
Solution:
change DATE -> DATETIME.
And now everything works good.
Anyway, thank you for answers.