I have a table that holds entries when the value changes, however I now have a need to get the value for each day between two dates.
So in the database I have the following:
2015-10-17 25
2015-10-12 20
2015-10-01 5
What I need is to get the values for the entire month
2015-10-01 5
2015-10-02 5
....
2015-10-12 20
2015-10-13 20
How would I achieve this? I have the below code
http://www.sqlfiddle.com/#!2/ca447e/1/0
CREATE PROCEDURE sp_GetMonthVals(IN StartDate DATETIME, IN EndDate DATETIME)
BEGIN
DECLARE CurrentDate DATETIME;
SET #CurrentDate = StartDate;
label1: WHILE #CurrentDate < #EndDate DO
SELECT #CurrentDate, DVal FROM Table1 WHERE MDate <= #CurrentDate ORDER BY MDate DESC LIMIT 1;
SET #CurrentDate = DATE_ADD(CurrentDate, INTERVAL 1 DAY);
END WHILE label1;
END;
CREATE TABLE Table1
(`id` int, `MDate` varchar(10), `DVal` int)
;
INSERT INTO Table1
(`id`, `MDate`, `DVal`)
VALUES
(1, '2015-10-17', 25),
(2, '2015-10-12', 20),
(3, '2015-10-01', 5)
;
CALL sp_GetMonthVals('2015-10-01', '2015-10-31');
I have managed to achieve this using the below, if anyone can improve the query then I'll accept their answer
DROP PROCEDURE IF EXISTS sp_GetMonthVals;
DELIMITER //
CREATE PROCEDURE sp_GetMonthVals(IN StartDate DATETIME, IN EndDate DATETIME)
BEGIN
DECLARE CurrentDate DATETIME;
SET #CurrentDate = StartDate;
DROP TABLE IF EXISTS _tmpMonthVals;
CREATE TABLE _tmpMonthVals (`MDate` DATETIME, `DVal` int);
label1: WHILE #CurrentDate < EndDate DO
INSERT INTO _tmpMonthVals SELECT #CurrentDate, DVal FROM Table1 WHERE MDate <= #CurrentDate ORDER BY MDate DESC LIMIT 1;
SET #CurrentDate = DATE_ADD(#CurrentDate, INTERVAL 1 DAY);
END WHILE label1;
SELECT * FROM _tmpMonthVals;
END//
DELIMITER ;
CREATE TABLE IF NOT EXISTS Table1
(`id` int, `MDate` DATETIME, `DVal` int)
;
INSERT INTO Table1
(`id`, `MDate`, `DVal`)
VALUES
(1, '2015-10-17', 25),
(2, '2015-10-12', 20),
(3, '2015-10-01', 5);
CALL sp_GetMonthVals('2015-10-01', '2015-10-31');
Related
I have a table name as 'records' field is 'dates', how to get missing dates in a table based on passing two dates like 2018-03-23,2018-03-30 using MySQL query
records :
id dates
------------
1 2018-03-23
2 2018-03-24
3 2018-03-27
4 2018-03-28
5 2018-03-30
Expected Result is missing dates: 25,26,29
Here's a SQL Server Solution
declare #date datetime=(Select min(date) from table)
declare #maxdate datetime = (Select max(date) from table)
while #date<=#maxdate
begin
if #date not in (Select date from table)
select #date
select #date=dateadd(dd, 1, #date)
end
Please check the example below:
CREATE TABLE #tmp (
my_date DATETIME
)
INSERT INTO #tmp (my_date) VALUES ('2016-01-01')
INSERT INTO #tmp (my_date) VALUES ('2016-01-02')
INSERT INTO #tmp (my_date) VALUES ('2016-01-04')
INSERT INTO #tmp (my_date) VALUES ('2016-01-05')
INSERT INTO #tmp (my_date) VALUES ('2016-01-07')
INSERT INTO #tmp (my_date) VALUES ('2016-01-08')
INSERT INTO #tmp (my_date) VALUES ('2016-01-10')
INSERT INTO #tmp (my_date) VALUES ('2016-01-11')
DECLARE #max_date DATETIME
SELECT #max_date = max(my_date) FROM #tmp
SELECT DATEADD(day,1,t1.my_date) as miss_date
FROM #tmp t1
LEFT JOIN #tmp t2 ON t1.my_date=DATEADD(day,-1,t2.my_date)
WHERE t2.my_date is null
AND t1.my_date<>#max_date
Also, please see: MySQL: Find Missing Dates Between a Date Range
I'm using following stored procedure to fill the date dimension. and it is giving following error
#1064 - You have an error in your SQL syntax; check the manual that
corresponds to your MySQL server version for the right syntax to use
near 'DELETE FROM Date_Dim SET v_full_date = p_start_date WHILE
v_full_date < p_end_d' at line 6
CREATE PROCEDURE datedimbuild (p_start_date DATE, p_end_date DATE)
BEGIN
DECLARE v_full_date DATE
DELETE FROM Date_Dim
SET v_full_date = p_start_date
WHILE v_full_date < p_end_date
DO
INSERT INTO Date_Dim
(
Full_Date ,
DayOfMonth ,
DayOfYear ,
DayOfWeek ,
Day_Name ,
Month_Number,
Month_Name,
Year,
Quarter
)
VALUES
(
v_full_date,
DAYOFMONTH(v_full_date),
DAYOFYEAR(v_full_date),
DAYOFWEEK(v_full_date),
DAYNAME(v_full_date),
MONTH(v_full_date),
MONTHNAME(v_full_date),
YEAR(v_full_date),
QUARTER(v_full_date)
);
SET v_full_date = DATE_ADD(v_full_date, INTERVAL 1 DAY)
END WHILE
END
You must delimit statements. Try this:
DELIMITER $$
CREATE PROCEDURE datedimbuild (p_start_date DATE, p_end_date DATE)
BEGIN
DECLARE v_full_date DATE;
DELETE FROM Date_Dim;
SET v_full_date = p_start_date;
WHILE v_full_date < p_end_date
DO
INSERT INTO Date_Dim
(
Full_Date ,
DayOfMonth ,
DayOfYear ,
DayOfWeek ,
Day_Name ,
Month_Number,
Month_Name,
Year,
Quarter
)
VALUES
(
v_full_date,
DAYOFMONTH(v_full_date),
DAYOFYEAR(v_full_date),
DAYOFWEEK(v_full_date),
DAYNAME(v_full_date),
MONTH(v_full_date),
MONTHNAME(v_full_date),
YEAR(v_full_date),
QUARTER(v_full_date)
);
SET v_full_date = DATE_ADD(v_full_date, INTERVAL 1 DAY);
END WHILE;
END $$
DELIMITER ;
USE
DELIMITER |
CREATE PROCEDURE datedimbuild (p_start_date DATE, p_end_date DATE)
BEGIN
DECLARE v_full_date DATE;
DELETE FROM Date_Dim;
SET v_full_date = p_start_date;
WHILE v_full_date < p_end_date
DO
INSERT INTO Date_Dim
(
Full_Date ,
DayOfMonth ,
DayOfYear ,
DayOfWeek ,
Day_Name ,
Month_Number,
Month_Name,
Year,
Quarter
)
VALUES
(
v_full_date,
DAYOFMONTH(v_full_date),
DAYOFYEAR(v_full_date),
DAYOFWEEK(v_full_date),
DAYNAME(v_full_date),
MONTH(v_full_date),
MONTHNAME(v_full_date),
YEAR(v_full_date),
QUARTER(v_full_date)
);
SET v_full_date = DATE_ADD(v_full_date, INTERVAL 1 DAY);
END WHILE;
END;
|
I have searched a lot, but cannot find a helpful answer:
i want to have a list of totals from a period the user defines by giving me a start and end date. The totals should every time being from the start date to beginning with the start date and add every row 1 day. so the last row gives the totals from start to end date.
example: - given period = start 2013-01-01 , end = 2013-01-31
total day 1 = 100
total day 2 = 0 (not listed in my totalsperday query, but should have a row in my final query)
total day 3 = 140
total day 4 = 20
...
final table should look like:
end day 1: 100
end day 2: 100
end day 3: 240
end day 4: 260
...
so i have a query who calculates all days:
SELECT '2013-01-01' as startdate, w.endDate
FROM
(
SELECT date('2013-01-01' + INTERVAL u.i*100 + v.i*10 + w.i DAY) AS endDate
FROM sysints AS u
JOIN sysints AS v
JOIN sysints AS w
WHERE ( u.i*100 + v.i*10 + w.i ) <=
(
SELECT DATEDIFF( '2013-01-31','2013-01-01') as ddff
)
) w
ORDER BY w.endDate ASC
and i have a query who calculates the totals per day
SELECT p.selldate, SUM(p.price) as totalPerDay
FROM products p
WHERE '2013-01-01' >= p.selldate <= '2013-01-31'
GROUP BY p.selldate
ORDER BY p.selldate ASC
now combining these two to get my final result is hard.
basically what the final query should look like is:
- make the sum of sumperday from day 1 to day 1
- make the sum of sumperday from day 1 to day 2
- make the sum of sumperday from day 1 to day 3
...
any help?
thx.
this is a simplified example of my final query.
Below is the sample. The idea is to obtain a initial data set ordered by date and having aggregate totals, implicit date range records. Then using the cursor you can pass through each row to get the final total column (amountCalc column in the sample) just by summarize the previous records - will work because you already have the columns ordered by date.
The procedure can have other input/ output parameters. Instead of getting info from table you can get data from one view, where the view can be already order by date asc. Is just a sample so can be customized as needed.
Good luck.
-- drop table `Balance`;
CREATE TABLE `Balance` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`date` DATE NOT NULL,
`account` varchar(30) NOT NULL,
`amount` DECIMAL(10,2) NOT NULL,
PRIMARY KEY (`id`)
);
INSERT INTO `Balance` (`date`, `account`, `amount`) VALUES
('2013-01-02', 'T355176', 8700),
('2013-01-03', 'T355176', 8900),
('2013-01-04', 'T355215', 33308),
('2013-01-03', 'T355215', 116581),
('2013-01-06', 'T812022', 275000),
('2013-01-02', 'T812063', 136500),
('2013-01-05', 'T812063', 11682),
('2013-01-06', 'T812064', 615100),
('2013-01-03', 'T812064', 25000),
('2013-01-02', 'T812085', 82500);
SELECT * FROM Balance WHERE date >= '2013-01-01' AND date <= '2013-01-06' ORDER BY date ASC;
CALL sp_getTotals('2013-01-01', '2013-01-06');
-- --------------------------------------------------------------------------------
-- Routine DDL
-- Note: comments before and after the routine body will not be stored by the server
-- --------------------------------------------------------------------------------
DELIMITER $$
CREATE DEFINER=`root`#`%` PROCEDURE `sp_getTotals`(IN startDate DATE, IN endDate DATE)
BEGIN
DECLARE dt DATE;
DECLARE amt DECIMAL(10,2);
DECLARE amtCalcPart DECIMAL(10,2);
DECLARE done INT DEFAULT 0;
DECLARE dtStart DATE;
DECLARE dtEnd DATE;
DECLARE cur1 CURSOR FOR SELECT date, amount FROM `TempMB`;
DECLARE cur2 CURSOR FOR SELECT startDate, endDate;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
DROP TEMPORARY TABLE IF EXISTS `TempMB`;
CREATE TEMPORARY TABLE IF NOT EXISTS `TempMB` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`date` DATE NOT NULL,
`amount` DECIMAL(10,2) NULL DEFAULT 0.00,
`amountCalc` DECIMAL(10,2) NULL DEFAULT 0.00,
PRIMARY KEY (`id`)
);
SET dtStart = DATE(startDate);
SET dtEnd = DATE(endDate);
WHILE dtStart <= dtEnd DO
INSERT INTO `TempMB` (`date`) SELECT dtStart;
SET dtStart = DATE_ADD(dtStart, INTERVAL 1 DAY);
END WHILE;
SELECT * FROM TempMB;
-- Fill temp table with info needed
UPDATE `TempMB` t
INNER JOIN
(
SELECT date, SUM(amount) AS amount
FROM Balance
WHERE
date >= startDate AND date <= endDate
GROUP BY date
ORDER BY date ASC
) b ON b.date = t.date
SET
t.amount = b.amount;
/*INSERT INTO `TempMB` (`date`, `amount`)
SELECT date, SUM(amount) AS amount
FROM Balance
WHERE
date >= startDate AND date <= endDate
GROUP BY date
ORDER BY date ASC;
*/
SET amtCalcPart = 0.00;
-- Initialise cursor
OPEN cur1;
-- USE BEGIN-END handler for cursor-control within own BEGIN-END block
BEGIN
DECLARE EXIT HANDLER FOR NOT FOUND BEGIN END;
-- Loop cursor throu temp records
LOOP
-- Get next value
FETCH cur1 INTO dt, amt;
-- Calculate amountCalc
SET amtCalcPart = (SELECT SUM(amount) as amt FROM `TempMB` WHERE Date <= dt);
UPDATE `TempMB` SET amountCalc = amtCalcPart WHERE date = dt;
END LOOP;
END;
-- Release cursor
CLOSE cur1;
SELECT * FROM TempMB;
END
I want to extract a count for every Date between two dates (#sdate,#edate) but it gives me only the count for the last day and not for all days.
How can i output all results? Here is my stored proc.
DELIMITER $$
USE `cmd_storeinfo`$$
DROP PROCEDURE IF EXISTS `test2`$$
CREATE DEFINER=`USER`#`%` PROCEDURE `test2`()
BEGIN
SET #sdate = (DATE_SUB(CURDATE(), INTERVAL 6 MONTH));
SET #edate = (CURDATE());
SET #x='';
SET #Y='';
WHILE #sdate <= #edate DO
SELECT COUNT(*) INTO #y
FROM cmd_storeinfo.strinfo
WHERE LiveDate <= #sdate AND DeinstallDate >= #sdate OR DeinstallDate IS
NULL AND LiveDate IS NOT NULL
AND CHAIN != 1 && CHAIN != 2 && CHAIN != 999
GROUP BY #sdate
SET #x = #sdate;
SET #sdate = (DATE_ADD(#sdate, INTERVAL 1 DAY));
END WHILE;
SELECT #x,#y;
END$$
DELIMITER ;
Thanks for you help.
Daniel
You should try to use temporary table. Here is a nice answer about it.
Something like this could work:
DELIMITER $$
USE `cmd_storeinfo`$$
DROP PROCEDURE IF EXISTS `test2`$$
CREATE DEFINER=`USER`#`%` PROCEDURE `test2`()
BEGIN
CREATE TEMPORARY TABLE tmpTable (currentDate DATE, startDate INT);
SET #sdate = (DATE_SUB(CURDATE(), INTERVAL 6 MONTH));
SET #edate = (CURDATE());
SET #x='';
SET #Y='';
WHILE #sdate <= #edate DO
INSERT INTO tmpTable (currentDate, startDate)
SELECT #sdate, COUNT(*)
FROM cmd_storeinfo.strinfo
WHERE LiveDate <= #sdate AND DeinstallDate >= #sdate OR DeinstallDate IS
NULL AND LiveDate IS NOT NULL
AND CHAIN != 1 && CHAIN != 2 && CHAIN != 999
GROUP BY #sdate
SET #sdate = (DATE_ADD(#sdate, INTERVAL 1 DAY));
END WHILE;
SELECT * FROM tmpTable;
DROP TEMPORARY TABLE IF EXISTS tmpTable;
END$$
DELIMITER ;
You should use Temporary table to store all values.
DELIMITER $$
USE `cmd_storeinfo`$$
DROP PROCEDURE IF EXISTS `test2`$$
CREATE DEFINER=`USER`#`%` PROCEDURE `test2`()
BEGIN
SET #sdate = (DATE_SUB(CURDATE(), INTERVAL 6 MONTH));
SET #edate = (CURDATE());
SET #x='';
SET #Y='';
CREATE TEMPORARY TABLE tmpTable (x datetime,y bigint); -- creating tmp table
WHILE #sdate <= #edate DO
SELECT COUNT(*) INTO #y
FROM cmd_storeinfo.strinfo
WHERE LiveDate <= #sdate AND DeinstallDate >= #sdate OR DeinstallDate IS
NULL AND LiveDate IS NOT NULL
AND CHAIN != 1 && CHAIN != 2 && CHAIN != 999
GROUP BY #sdate
SET #x = #sdate;
insert into tmpTable (x,y) values (#x,#y); -- inserting values
SET #sdate = (DATE_ADD(#sdate, INTERVAL 1 DAY));
END WHILE;
SELECT x,y from tmpTable order by x; -- output temp table results
END$$
DELIMITER ;
Hi how can I make the following script to insert work.
First to check if table Exists if yes insert into table only, and I only want to insert into the table if the date range is not already in the table. Otherwise do select into table.
DECLARE #date1 datetime
DECLARE #date2 datetime
DECLARE #dailyEnd1 varchar(12)
DECLARE #dailyEnd2 varchar(12)
DECLARE #column varchar(100)
DECLARE #Script varchar(8000)
SET #date1 = '09 jan 2012'
SET #date2 = '15 jan 2012'
SET #dailyEnd1 = #date1
SET #dailyEnd2 = #date2
IF OBJECT_ID('tempdb..#table1') is not null
BEGIN
IF NOT EXIST (SELECT MinDate, MaxDate FROM #table1
WHERE MinDate = '02 Jan 2012' AND MaxDate = '08 jan 2012'
GROUP BY MinDate, MaxDate)
BEGIN
INSERT INTO #table1 (MinDate, MaxDate, [Week], OutletID, OutletName, Transactions, Spend)
SELECT min(dailyEnd-1), max(dailyEnd-1),
convert(varchar(12),Min(dailyEnd-1), 104)+'-'+convert(varchar(12),MAX(dailyEnd-1),104),
OutletID, OutletName,
sum(Transactions), sum(Sales)
FROM #table2 (NOLOCK)
WHERE dailyEnd-1 >= #dailyEnd1
AND dailyEND-1 <= #dailyEnd2
GROUP BY OutletID, OutletName
END
END
ELSE
BEGIN
SELECT min(dailyEnd-1) as MinDate, max(dailyEnd-1) as MaxDate,
convert(varchar(12),Min(dailyEnd-1), 104)+'-'+convert(varchar(12),MAX(dailyEnd-1),104) as [Week], OutletID, OutletName, sum(Transactions) as Transactions, sum(Sales) as Spend
INTO #table1
FROM #table2 (NOLOCK)
WHERE dailyEnd-1 >= #dailyEnd1
AND dailyEND-1 <= #dailyEnd2
GROUP BY OutletID, OutletName
END
Thanks
Move your NOT EXISTS clause down in the WHERE after your INSERT.
Meaning, only insert where NOT EXISTS for the date range.