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 ;
Related
I have a routine. But it' s too slow. How can I improve the query?
My records: http://www.sqlfiddle.com/#!9/14cceb/1/0
My query:
CREATE DEFINER = 'root'#'localhost'
PROCEDURE example.ssa()
BEGIN
drop table if exists gps_table;
drop table if exists exam_datas;
CREATE TEMPORARY TABLE gps_table(ID int PRIMARY KEY AUTO_INCREMENT,timei
int,
trun_date_time datetime, tadd_meter int, tin_here int null);
insert into gps_table(timei,trun_date_time,tadd_meter,tin_here) select
imei, run_date_time, add_meter, in_here from example_table;
CREATE TEMPORARY TABLE exam_datas(ID int PRIMARY KEY AUTO_INCREMENT,vimei
int, vbas_run_date_time datetime, vbit_run_date_time datetime, vdifff int);
select tin_here from gps_table limit 1 into #onceki_durum;
select count(id) from gps_table into #kayit_sayisi;
set #i = 1;
set #min_mes = 0;
set #max_mes = 0;
set #frst_id = 0;
set #imei = 0;
set #run_date_time = '0000-00-00 00:00:00';
set #run_date_time2 = '0000-00-00 00:00:00';
myloop: WHILE (#i <= #kayit_sayisi) DO
select tin_here from gps_table where id = #i into #in_here_true;
if (#in_here_true = 1) then
select id,trun_date_time, tadd_meter from gps_table where id = #i into #frst_id,#run_date_time2, #min_mes;
select id from gps_table where id > #frst_id and tin_here =0 order by id asc limit 1 INTO #id;
SET #id = #id-1;
select id, timei, trun_date_time, tadd_meter from gps_table
where id = #id and tin_here =1 limit 1 into #i, #imei, #run_date_time, #max_mes;
if(#i-#frst_id>3) then
set #i:=#i+1;
insert into exam_datas(vimei,vbas_run_date_time,vbit_run_date_time,vdifff) Values (#imei, #run_date_time2, #run_date_time, #max_mes-#min_mes);
SELECT * FROM exam_datas;
SET #asd =1;
elseif 1=1 then
set #i:=#i+1;
End if;
ELSEIF 1=1
THEN SET #i:=#i+1;
End if;
IF (#i = #kayit_sayisi)
THEN set #tamam =1; LEAVE myloop;
END IF;
END WHILE myloop;
select DISTINCT * from exam_datas;
drop table if exists exam_datas;
drop table if exists gps_table;
END
I need: id= 6 first true and id= 11 last_true
firs_trure - last_true = 304-290= 14
id=14 first true and id=18 last_true
firs_true - last_true = 332-324= 8
This routine is too slow.
MySql version is 5.7 and There are 2 milions record in the table.
UPDATE:
Query is here. HERE
Thank you #LukStorms
It's possible to get such results in 1 query.
Thus avoiding a WHILE loop over records.
This example works without using window functions. Just using variables inside the query to calculate a rank. Which is then used to get the minimums and maximums of the groups.
select
imei,
min(run_date_time) as start_dt,
max(run_date_time) as stop_dt,
max(add_meter) - min(add_meter) as diff
from
(
select imei, id, run_date_time, add_meter, in_here,
case
when #prev_imei = imei and #prev_ih = in_here then #rnk
when #rnk := #rnk + 1 then #rnk
end as rnk,
#prev_imei := imei as prev_imei,
#prev_ih := in_here as prev_ih
from example_table t
cross join (select #rnk := 0, #prev_ih := null, #prev_imei := null) vars
order by imei, id, run_date_time
) q
where in_here = 1
group by imei, rnk
having count(*) > 4
order by imei, min(id);
In the procedure such query can be used to fill that final temporary table.
A test on db<>fiddle here
i am making a stored procedure to give cashback based on the total transactions by a single person a month but when called it shows null value for cashback get
CREATE DEFINER=`root`#`localhost` PROCEDURE `stored_procedure_cashback`(IN a INT, IN b INT)
BEGIN
DECLARE cashback_get INT;
DECLARE total INT;
SELECT customers.`id_customers`, customers.`customers_name`, MONTH(transaction.`transaction_date`) AS month,
YEAR(transaction.`transaction_date`) AS year,
SUM((transaction_detail.`ammount`*transaction_detail.`price_per_piece`)-transaction_detail.`discount`) AS total,
cashback_get
FROM transaction_detail
INNER JOIN transaction ON transaction_detail.`id_transaction`=transaction.`id_transaction`
INNER JOIN customers ON transaction.`id_customers`=customers.`id_customers`
WHERE MONTH(transaction.`transaction_date`) = a AND YEAR(transaction.`transaction_date`) = b
GROUP BY customers.`id_customers`;
IF (total >= 20000) THEN
SET cashback_get = 2000;
ELSE
SET cashback_get = 0;
END IF;
You mised to put the result as OUT parameter.
CREATE DEFINER=`root`#`localhost` PROCEDURE.
`stored_procedure_cashback`(IN a INT, IN b INT, OUT cashback_get INT)
BEGIN
DECLARE total INT;
SELECT Sum( etc etc) into total
From table
etc etc
IF total >= 20000 Then
SET cashback_get = 2000;
ELSE
SET cashback_get = 0;
END IF;
END;
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');
I have a question about mysql stored procedure and variables;
Table Name : es_adwords
Fields : id # image_source # image_link # computer_id # is_all_pc # image_state # banner_size
I want to create stored procedure that should search computer_id = {pc_number} and image_state = 0.
If not, stored procedure should return to be equal to is_all_pc = 1.
DELIMITER $$
DROP PROCEDURE IF EXISTS `GetAdwordsBanner` $$
DELIMITER $$
CREATE PROCEDURE `GetAdwordsBanner`(IN compid INT)
BEGIN
SET #result_id := 0;
SELECT #result_id := id FROM es_adwords WHERE image_state = 1 AND computer_id = compid ORDER BY id DESC LIMIT 0,1;
IF (#result_id != 0) THEN
SELECT image_source,image_link,banner_size FROM es_adwords WHERE image_state = 1 AND computer_id = compid ORDER BY id DESC LIMIT 0,1;
ELSE
SELECT image_source,image_link,banner_size FROM es_adwords WHERE image_state = 1 AND is_all_pc = 1 ORDER BY id DESC LIMIT 0,1;
END IF;
END $$
DELIMITER ;
Sincerely Yours...
Your logic has a problem. I would rewrite this to:
DELIMITER $$
CREATE PROCEDURE `GetAdwordsBanner`(IN compid INT)
BEGIN
-- use a local variable instead of a user variable
DECLARE result_count INT;
-- count how many rows are matching
SELECT COUNT(*) INTO result_id FROM es_adwords WHERE image_state = 1 AND computer_id = compid;
-- if there are matches
IF result_count > 0 THEN
-- return the first matching row
SELECT image_source,image_link,banner_size FROM es_adwords WHERE image_state = 1 AND computer_id = compid ORDER BY id DESC LIMIT 0,1;
ELSE
-- return the default one
SELECT image_source,image_link,banner_size FROM es_adwords WHERE image_state = 1 AND is_all_pc = 1 ORDER BY id DESC LIMIT 0,1;
END IF;
END $$
DELIMITER ;
This should work.
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;
|