I have two stored procedures in MySql. One of them does the calculation and returns everything in groups. With another stored procedure, I have a WHILE statement that runs for each month and calls the first stored procedure. I want to get the result of each group and save them in a table.
The code is something like:
CREATE PROCEDURE `first`(IN `start` date, **it should be list of items** )
begin
SET result = 0;
SELECT
item.name,
sum(amount) *INTO result*
FROM
FOO
INNER JOIN
BAR ON id = id
WHERE
date(someDate) < date(start)
group by something;
end
And the runner is something like:
CREATE PROCEDURE `runner`(IN `from` date, IN `to` date)
BEGIN
set dateTo = date(to);
set dateFrom = date(from);
WHILE DATE(dateFrom) <= DATE(dateTo) DO
call first(dateFrom, #res);
// here I need another loop through all results of the first procedure to insert each one of them in the following line.
insert into table_x (**some values which have been returned**);
SET dateFrom = DATE_ADD(dateFrom, INTERVAL 1 month);
END WHILE;
END
I don-' think that the loop and the second procedure ist really necessary
MySQL can't return table arrays or something of that kind, but you can use temporary tables
DELIMITER $$
CREATE PROCEDURE `first`(IN `start` date )
begin
DROP TEMPORARY TABLE IF EXISTS myTable;
CREATE TEMPORARY TABLE myTABLE
SELECT
item.name,
sum(amount)
FROM
FOO
INNER JOIN
BAR ON id = id
WHERE
date(someDate) < date(start)
group by something;
end$$
DELIMITER ;
Outer procdudre
DELIMITER $$
CREATE PROCEDURE `runner`(IN `_from` date, IN `_to` date)
BEGIN
set dateTo = date(_to);
set dateFrom = date(_from);
WHILE DATE(dateFrom) <= DATE(dateTo) DO
call first(dateFrom, #res);
insert into table_x (SELECT * FROM myTable);
SET dateFrom = DATE_ADD(dateFrom, INTERVAL 1 month);
END WHILE;
END$$
DELIMITER ;
You ca make dynamic sql work with different variables
DELIMITER $$
CREATE PROCEDURE `first`(IN `_start` date , IN _group varchar(100))
begin
DROP TEMPORARY TABLE IF EXISTS myTable;
SET #sql := CONCAT("
CREATE TEMPORARY TABLE myTABLE
SELECT
item.name,
sum(amount)
FROM
FOO
INNER JOIN
BAR ON id = id
WHERE
date(someDate) < date(",_gRoup,")
group by",_goup,";");
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
end$$
DELIMITER ;
This might work, if all ** some values ** are replaced.
Minimal version of MySQL needed is 8.0 (or an equivalent MariaDB version).
The two variables #from and #to are set to let this script know from which data to which date is needed.
This code is untested, because OP wrote "I have two stored procedures in MySql", but he uses things like "** some values **", which make the two stored procedures invalid (sigh).
Final remark: It is, of course, possible to wrap this complete statement into a stored procedure. (If above corrections are made)
set #from = '2021-05-01';
SET #to = '2021-06-13';
insert into table_x (** some values **)
WITH recursive dates AS (
SELECT #from as d
UNION ALL
SELECT date_add(d, INTERVAL 1 DAY)
FROM dates
WHERE d<#to
)
SELECT d, **some values which have been returned**
FROM dates
CROSS JOIN (
SELECT
item.name,
sum(amount)
FROM
FOO
INNER JOIN
BAR ON id = id
WHERE
date(someDate) < date(d)
group by something) sq
Related
I am creating some reporting which summarises user actions (clicks) from an online job board.
The MYSQL tables are structured so that there is one table for each days activities. The table names are standard (except for the date) e.g. 'User_Clicks_DD_MM_YYY'
I want to select from all of the tables (including future tables that have not yet been created) without having to revisit the code each day.
Does anyone know of a way that I can do this?
here is one way to approach this, it is a stored procedure that builds a query
what this does is, loops through a range of dates (you can substitute now() for the last date) and checks if a table exists for a particular date. if it does exist then it adds it to a select statement string. then the string is executed at the end of the proc.
create table tab_01_01_2020 (id int);
create table tab_02_01_2020 (id int);
insert into tab_01_01_2020 values (1);
insert into tab_02_01_2020 values (1);
DELIMITER $$
DROP PROCEDURE IF EXISTS test$$
CREATE PROCEDURE test()
BEGIN
DECLARE count INT DEFAULT 0;
DECLARE mydate DATE;
set mydate = '2020/01/01';
set #qry='select 0 as id where 1 = 0';
WHILE mydate < '2020/02/01' DO
SET count = count + 1;
set #day = (SELECT RIGHT(CONCAT('0',DAY(mydate)), 2));
set #mon = (SELECT RIGHT(CONCAT('0',MONTH(mydate)), 2));
set #tab = CONCAT('tab_',#day,'_',#mon,'_',YEAR(mydate));
IF (SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = #tab) = 1
THEN
set #qry = CONCAT(#qry, ' union select id from ', #tab);
END IF;
SET mydate = DATE_ADD(mydate, INTERVAL 1 DAY);
END WHILE;
select #qry;
prepare stmt from #qry;
execute stmt;
deallocate prepare stmt;
END$$
DELIMITER ;
call test();
I'm trying to create a stored procedure with mysql. The idea is not check if the first request is empty or not, and do it if it's not, or do the second one if the first is empty.
My code, symplified version.
DELIMITER //
CREATE PROCEDURE HFTester(idTest INT)
BEGIN
IF (SELECT * FROM `foo` WHERE id = idTest) != NULL
THEN (SELECT * FROM `foo` WHERE id = idTest;)
ELSE (SELECT * FROM `bar` WHERE id = idTest;)
END IF;
END //
DELIMITER;
The procedure is saved, but when I execute it, i get an empty result.
So I searched the Internet, and I found ifnull .
I then tried to apply it to my case:
DELIMITER //
CREATE PROCEDURE HFTester(idFiche INT)
BEGIN
SELECT IFNULL(
(SELECT * FROM `foo` WHERE id = idTest;),
(SELECT * FROM `bar` WHERE id = idTest;)
);
END //
DELIMITER;
I'm pretty sure the IFNULL can't work, but is there a way to do this if statement in MySQL, or am I force to do it in php?
Victor.
I wanted to write a trigger which deletes the oldest DB entry if a new one is inserted and the rowcount is larger than 3600 rows. Unfortunately, there is a error(1064) in line 7, but I don't know how to fix it. The column time if defined by using DATETIME in mysql.
CREATE TRIGGER maxRows BEFORE INSERT ON table1
FOR EACH ROW
BEGIN
IF ((SELECT COUNT(*) FROM table1) = 3600) THEN
DELETE FROM table1
ORDER BY time ASC
LIMIT 1;
END IF;
END;
As you have some DML sentences inside your trigger, try changing the delimiters
DELIMITER $$
CREATE TRIGGER maxRows BEFORE INSERT ON table1
FOR EACH ROW
BEGIN
IF ((SELECT COUNT(*) FROM table1) = 3600) THEN
DELETE FROM table1
ORDER BY time ASC
LIMIT 1;
END IF;
END;
END $$
DELIMITER ;
i am trying to write a stored procedure for mysql, and basicly, it will select one id, and update selected id's operationdate.
DELIMITER //
CREATE PROCEDURE getID(
IN proc_intervaldate datetime
)
BEGIN
DECLARE RUserID BIGINT;
SELECT
UserID
INTO RUserID
FROM Tasks
WHERE OperationDate < proc_intervaldate
LIMIT 1 ;
UPDATE Tasks SET OperationDate = now() WHERE UserID = RUserID;
SELECT RUserID ;
END //
DELIMITER ;
but when i use this, procedure, it will return UserID but not update, if i comment
SELECT RUserID
then, it updates, but no data returns.
when I use this, procedure, it will return UserID but not update, if I comment 'SELECT RUserID;' then, it updates, but no data returns.
You can change definition of stored procedure to use an OUT parameter rather than just IN. With that, you can just capture the OUT value on the same OUT parameter, in your scripting language. Meaning you need not execute:
SELECT RUserID ;
in your stored procedure.
Change your SP definition as below:
DELIMITER //
CREATE PROCEDURE getID( IN proc_intervaldate datetime, OUT RUserID bigint )
BEGIN
SELECT
UserID INTO RUserID
FROM Tasks
WHERE
OperationDate < proc_intervaldate
LIMIT 1 ;
UPDATE Tasks SET OperationDate = now() WHERE UserID = RUserID;
END;
//
DELIMITER ;
You can call this stored procedure like, for example, at MySQL console:
SET #RUserID := 0;
CALL getID( now(), #RUserID );
SELECT #RUserID;
Refer to:
MySQL: CALL procedure syntax
To get back a value from a procedure using an OUT or INOUT parameter,
pass the parameter by means of a user variable, and then check the
value of the variable after the procedure returns.
Following is my Stored Procedure
DELIMITER $$
USE `us_db`$$
DROP PROCEDURE IF EXISTS `getTransactionDetails`$$
CREATE DEFINER=`root`#`localhost` PROCEDURE `getTransactionDetails`(IN _MainDB VARCHAR(32),
IN _mobile VARCHAR(50),
IN _market_id VARCHAR(50),
IN _from DATE,
IN _to DATE)
BEGIN
SELECT
transaction_id AS txn_id,
DATE_FORMAT(createdon,"%d-%b-%Y %H:%i:%S") AS createdon,
order_id,
order_conv_total AS amount,
msisdn AS msisdn,
channel_id,
transmode_id,
statusid,
(SELECT fullname FROM _MainDB.entities WHERE entity_id=retailer_id) AS retailer,
FROM `us_transaction` `t` WHERE
t.market_id = _market_id AND msisdn = _mobile AND t.createdon BETWEEN CONCAT(DATE(_from)," 00:00:00") AND CONCAT(DATE(_to)," 23:59:59") ORDER BY t.createdon DESC LIMIT 100;
END$$
DELIMITER ;
Now the issue is that the retailer name is stored in a separate DB which i want to call through _MainDB. This DB name is coming as an argument, but it's not coming properly because the _MainDB is considered as varchar type. How can I take the DB name as an argument in a stored procedure???
user variable and CONCAT function;
DECLARE STR VARCHAR(1000)
SET #STR = 'SELECT
transaction_id AS txn_id,
........
(SELECT fullname FROM
'
SET #STR = CONCAT(#STR,#_MAINDB)
SET #STR = CONCAT(#STR,'.entities ..................')
PREPARE STMT FROM #STR
EXECUTE STMT