Creating MySQL Temporary Table then Assign CRUD From It - mysql

i have created a stored procedure which have logic like this:
getting the data result from 2 tables then create temporary table based on it (the data range is selected using two parameter start date and end date).
select few columns from the temporary table then assign to another table (eg. X)
update the table (X).
this is my stored procedure syntax:
DELIMITER $$
USE `sre`$$
DROP PROCEDURE IF EXISTS `sp_checkPotentialProductf`$$
CREATE DEFINER=`root`#`localhost` PROCEDURE `sp_checkPotentialProductf`(IN sdate DATE, IN edate DATE)
BEGIN
DECLARE sumtotal INT DEFAULT 0;
DECLARE first_margin DOUBLE;
DECLARE count_rows INT DEFAULT 0;
DECLARE startnum INT DEFAULT 0;
DECLARE start_mrg DOUBLE;
DECLARE adder DOUBLE;
/* assign table temporary and select the values */
CREATE TEMPORARY TABLE IF NOT EXISTS vShowTopSellingQuantitys AS
SELECT
`mt_pesanan`.`ms_langganan_idms_langganan` AS `idms_langganan`,
`mt_pesanan`.`ms_langganan_idms_kodebarang` AS `idms_kodebarang`,
`md`.`nama` AS `nama`,
`mt_pesanan`.`quantity` AS `quantity`,
`mt_pesanan`.`harga` AS `harga`,
`mt_pesanan`.`jumlah` AS `jumlah`,
`mt_pesanan`.`discount` AS `discount`,
`mt_pesanan`.`tgl_pesan` AS `tgl_pesan`,
SUM(`mt_pesanan`.`quantity` ) AS `sum_product`
FROM `mt_pesanan` JOIN `ms_barang` `md`
WHERE ((`mt_pesanan`.`tgl_pesan` <= edate) AND (`mt_pesanan`.`tgl_pesan` >= sdate))
AND (md.`idms_kodebarang` = `mt_pesanan`.`ms_langganan_idms_kodebarang`)
GROUP BY `mt_pesanan`.`ms_langganan_idms_kodebarang`
ORDER BY SUM(`mt_pesanan`.`quantity` ) DESC;
/* end assign table temporary */
/* assign values to variables */
SELECT SUM(sum_product) INTO sumtotal FROM `vShowTopSellingQuantitys`;
SELECT COUNT(sum_product) INTO count_rows FROM `vShowTopSellingQuantitys`;
SELECT (sum_product/sumtotal)*100 INTO first_margin FROM `vShowTopSellingQuantitys` LIMIT 1;
/* truncate database tmp*/
TRUNCATE tmp_produkpotensial;
/*creating algorithm to analyze the percentage quantity/total */
SET startnum = 1;
/*show result with percentage*/
SELECT `idms_kodebarang`, `nama`, sum_product , ((sum_product/sumtotal)*100) AS 'pecentage_margin' FROM `vShowTopSellingQuantitys`;
/*result execution from temporary table to analyze potential product */
INSERT INTO tmp_produkpotensial(idms_kodebarang,nama,percentage_margin)
SELECT `idms_kodebarang`, `nama`, ((sum_product/sumtotal)*100) AS 'percentage_margin' FROM `vShowTopSellingQuantitys`;
/* update the sum total of percentage */
WHILE(count_rows >= startnum) DO
IF(startnum = 1) THEN
SET start_mrg = 0;
UPDATE tmp_produkpotensial SET tmp_produkpotensial.sum_margin = (percentage_margin + start_mrg) WHERE id_barang = startnum;
ELSE
SELECT sum_margin INTO start_mrg FROM tmp_produkpotensial WHERE id_barang = (startnum - 1);
UPDATE tmp_produkpotensial SET tmp_produkpotensial.sum_margin = (percentage_margin + start_mrg) WHERE id_barang = startnum;
END IF;
/* Assign Update to Update Sum Margin Column */
SET startnum = startnum + 1;
END WHILE;
END$$
DELIMITER ;
The stored procedure is successfully compiled, but when i call the stored procedure it always returns 0 rows.
syntax to call the stored procedure:
CALL `sp_checkPotentialProductf`('2012-12-31','2012-01-01');
My Questions:
can temporary table is used again to create further CRUD statement?
is there any ideas where the fails goes on?
thanks

okay, i have discovered a mistake. The method to call the stored procedure is
CALL `sp_checkPotentialProductf`(2012-12-31,2012-01-01);
without the quotes.

Related

How to reduce time to process data in procedure of mysql

Thank you forum...please help me..
I have table which contain TagName and other table contains taglog .im passing tag names to procedure called GetAvg which will return avg of all tags.it works well, but it takes about 35 sec to show 100 tag values.how to reduce time .please help me im new in database.
DELIMITER $$
CREATE DEFINER=`root`#`localhost` PROCEDURE `GetAvg`(IN FromTime datetime, IN ToTime datetime)
BEGIN
DECLARE no_more_alarms INT DEFAULT 0;
DECLARE TempTagName VARCHAR(45);
DECLARE val FLOAT;
DECLARE cur_tag CURSOR FOR
select Tag_AVG from Report
where(Tag_AVG IS NOT NULL );
DECLARE CONTINUE HANDLER FOR NOT FOUND
SET no_more_alarms = 1;
DROP TABLE IF EXISTS `tempAVG`;
CREATE TABLE tempAVG (
val FLOAT
);
OPEN cur_tag;
FETCH cur_tag INTO TempTagName;
REPEAT
SELECT AVG(value) INTO val
FROM jas_taglog
WHERE ((TagId = (select TagId from jas_tags where jas_tags.Name = TempTagName)) AND jas_taglog.LogTime between FromTime and ToTime) ;
INSERT INTO tempAvg(Val)
VALUES (val);
FETCH cur_tag INTO TempTagName;
UNTIL no_more_alarms = 1
END REPEAT;
CLOSE cur_tag;
SELECT * FROM tempAVG;
END
You are manually implementing loops that could be written in a single query:
...
BEGIN
INSERT INTO tempAvg
SELECT AVG(jas_taglog.value)
FROM jas_taglog
JOIN jas_tags USING (TagId)
JOIN Report ON jas_tags.Name = Tag_AVG
WHERE jas_taglog.LogTime BETWEEN FromTime AND ToTime
GROUP BY Tag_AVG;
END

Insert results of a stored procedure into an existing table

I have a table called Percentages with a Column called 5StarResults, I would like to populate this with the results of a stored procedure names 5star.
When I use 'Call 5star' it returns just a percentage, I would like this percentage inserted into the Percentages table.
Please can you assist, I have tried to edit the procedure to include an Insert but it always returns saying 0 rows inserted.
Thank you
edit,
Stored Procedure is as follows
BEGIN
declare Rating5Total int default 5;
declare Rating5Win int default 5;
declare 5StarPerformance decimal;
set Rating5Total = (select COUNT(Ratings) from vHighPerformance where Ratings = 7);
set Rating5Win = (select COUNT(Results) from vHighPerformance where Ratings = 7 and Results = 1);
set 5StarPerformance = Rating5Win*100.0/Rating5Total;
Select 5StarPerformance;
END
If an option is to do the INSERT in the same stored procedure, the following code should work:
CREATE PROCEDURE `5star`()
BEGIN
DECLARE Rating5Total INT DEFAULT 5;
DECLARE Rating5Win INT DEFAULT 5;
DECLARE 5StarPerformance DECIMAL(18, 3);
SET Rating5Total := (SELECT COUNT(Ratings) FROM vHighPerformance WHERE Ratings = 7);
SET Rating5Win := (SELECT COUNT(Results) FROM vHighPerformance WHERE Ratings = 7 AND Results = 1);
SET 5StarPerformance := Rating5Win*100.0/Rating5Total;
/* INSERT INTO percentages (percentage) VALUES (5StarPerformance); */
INSERT INTO percentages (id, percentage) VALUES (1, 5StarPerformance)
ON DUPLICATE KEY UPDATE percentage = 5StarPerformance;
SELECT 5StarPerformance;
END$$
An example can be seen in SQL Fiddle.
UPDATE
If you need one single record on table percentages, you can make a UPSERT. See the updated code.

How i can use variable from a select to call a stored procedure?

My problem it's this code.
DELIMITER $$
DROP PROCEDURE IF EXISTS agregar_abono$$
CREATE PROCEDURE agregar_abono(IN pid_cliente BIGINT, IN pfecha_abono DATE, IN pmonto_abono FLOAT)
BEGIN
DECLARE #idabono BIGINT;
-- OTHER CODE ...
SELECT id_abono AS idabono FROM abono WHERE fk_cliente = pid_cliente ORDER BY id_abono DESC LIMIT 1;
SELECT CONCAT('>', idabono);
CALL cobrar_abono(pid_cliente, vid_abono);
END $$
The procedure of the two SELECT return:
idabono = 52 --> good! (in the first select)
CONCAT('>', idabono) = null ---> what??
I don't know because don't stored the result in this variable to use in a stored procedure. I use a AS to store the variable.
The header of stored procedure to call is :
CREATE PROCEDURE cobrar_abono(IN pid_cliente BIGINT, IN pid_abono BIGINT)
Are you looking for this?
...
DECLARE idabono BIGINT;
-- OTHER CODE ...
SET idabono = (SELECT id_abono
FROM abono
WHERE fk_cliente = pid_cliente
ORDER BY id_abono DESC
LIMIT 1);
The SELECT statement itself probably can be replaced with
SET idabono = (SELECT MAX(id_abono)
FROM abono
WHERE fk_cliente = pid_cliente);

referring to the already fetched results in a query within the same query

So suppose I have this table with 4 columns:
id content parent timestamp
whereby the parent column refers to an id of another entry in the table
I want to accomplish the following:
Select the first 50 rows from the table Ordered by the following:
for each row,
if(parent = 0){
add row to resultset, ordered by timestamp
}
else if (parent != 0){
if parent is in the list of rows already fetched so far by the query,
add row to resultset, ordered by the timestamp
otherwise, wait until the parent gets fetched by the query
(assuming it gets fetched at all since there we're only getting the first 50 rows)
}
this ordering logic is somewhat complicated, and I'm wondering if it's even possible to accomplish this using MYSQL ORDER BY statement in a single query WITHOUT having to resort to subqueries? Perhaps we could set and use variables? But how would the ORDER BY statement will be implemented?
Here's a solution using variables which I incorporated into a procedure with a loop using an outer join and a temporary table to hold the unused inputdata but no subqueries.
Delete any old version of the procedure and set the delimiter
DROP PROCEDURE IF EXISTS order_proc;
DELIMITER ;;
Start writing the procedure
CREATE PROCEDURE order_proc()
BEGIN
DECLARE n INT DEFAULT 50;
DECLARE m INT DEFAULT 0;
DECLARE i INT DEFAULT 0;
DECLARE custom_limit INT DEFAULT 0;
DROP TABLE IF EXISTS pre_resultset;
CREATE TABLE pre_resultset LIKE input_data;
ALTER TABLE pre_resultset MODIFY id INT;
ALTER TABLE pre_resultset DROP PRIMARY KEY;
ALTER TABLE pre_resultset ADD COLUMN iid INT PRIMARY KEY NOT NULL AUTO_INCREMENT FIRST;
SELECT n INTO custom_limit;
Set SQL_SELECT_LIMIT = custom_limit;
INSERT INTO pre_resultset SELECT NULL,id, content, parent, timestamp FROM input_data WHERE parent = 0 ORDER BY timestamp;
Set SQL_SELECT_LIMIT = default;
DROP TABLE IF EXISTS unused_input_data;
CREATE TABLE unused_input_data LIKE input_data;
ALTER TABLE unused_input_data ADD null_col VARCHAR(1);
SELECT COUNT(*) FROM pre_resultset INTO m;
WHILE m<n DO
SELECT COUNT(*) FROM pre_resultset INTO m;
TRUNCATE unused_input_data;
INSERT INTO unused_input_data SELECT input_data.id, input_data.content, input_data.parent, input_data.timestamp, pre_resultset.id AS null_col FROM input_data LEFT OUTER JOIN pre_resultset on input_data.id = pre_resultset.id WHERE pre_resultset.id IS NULL ;
SELECT n-m INTO custom_limit;
Set SQL_SELECT_LIMIT = custom_limit;
INSERT INTO pre_resultset SELECT NULL, unused_input_data.id, unused_input_data.content, unused_input_data.parent, unused_input_data.timestamp FROM unused_input_data JOIN pre_resultset WHERE unused_input_data.parent = pre_resultset.id ORDER BY unused_input_data.timestamp;
Set SQL_SELECT_LIMIT = default;
SELECT COUNT(*) FROM pre_resultset INTO i;
SELECT (IF( i = m, n, i)) INTO m;
END WHILE;
SELECT id, content, parent, timestamp FROM pre_resultset AS resultset;
DROP TABLE IF EXISTS pre_resultset;
DROP TABLE IF EXISTS unused_input_data;
End;
;;
Change the delimeter back
DELIMITER ;
Run the procedure
CALL order_proc();

Temporary Table in Stored Functions?

I'm writing a function that I need to use either a TABLE variable for (I hear they don't exist in MySQL) or a temporary table.
However, it seems that temporary tables only seem to work in stored procedures, not functions. I keep getting this error:
Explicit or implicit commit is not allowed in stored function or
trigger.
What I'm trying to build is a solution to an earlier question of mine. It's a function that receives a start date, an end date, and a comma-deliminated string. It first finds all the months between the start and end date and saves them as individual records in the first temporary table. It then parses out the comma-deliminated string and saves those into a second temporary table. Then it does a select join on the two, and if records are present, it returns true, otherwise false.
My intention is to use this as part of another queries WHERE clause, so it needs to be a function and not a stored procedure.
How can I use temporary tables in stored functions? And if I can't, what can I do instead?
Here's my (currently broken) function (or as a gist):
-- need to parse out a string like '4,2,1' and insert values into temporary table
-- MySQL doesn't have a native string split function, so we make our own
-- taken from: http://blog.fedecarg.com/2009/02/22/mysql-split-string-function/
DROP FUNCTION IF EXISTS SPLIT_STR;
CREATE FUNCTION SPLIT_STR(x VARCHAR(255), delim VARCHAR(12), pos INT) RETURNS VARCHAR(255)
RETURN REPLACE(SUBSTRING(SUBSTRING_INDEX(x, delim, pos), LENGTH(SUBSTRING_INDEX(x, delim, pos -1)) + 1), delim, '');
-- need to find all months between the start and end date and insert each into a temporary table
DROP FUNCTION IF EXISTS months_within_range;
DELIMITER //
CREATE FUNCTION months_within_range(starts_at DATE, ends_at DATE, filter_range VARCHAR(255)) RETURNS TINYINT
BEGIN
DROP TABLE IF EXISTS months_between_dates;
DROP TABLE IF EXISTS filter_months;
CREATE TEMPORARY TABLE months_between_dates (month_stuff VARCHAR(7));
CREATE TEMPORARY TABLE filter_months (filter_month VARCHAR(7));
SET #month_count = (SELECT PERIOD_DIFF(DATE_FORMAT(ends_at, "%Y%m"), DATE_FORMAT(starts_at, "%Y%m")));
-- PERIOD_DIFF only gives us the one month, but we want to compare to, so add one
-- as in, the range between 2011-01-31 and 2011-12-01 should be 12, not 11
INSERT INTO months_between_dates (month_stuff) VALUES (DATE_FORMAT(starts_at, "%Y-%m"));
SET #month_count = #month_count + 1;
-- start he counter at 1, since we've already included the first month above
SET #counter = 1;
WHILE #counter < #month_count DO
INSERT INTO months_between_dates (month_stuff) VALUES (DATE_FORMAT(starts_at + INTERVAL #counter MONTH, "%Y-%m"));
SET #counter = #counter + 1;
END WHILE;
-- break up the filtered string
SET #counter = 1;
-- an infinite loop, since we don't know how many parameters are in the filtered string
filters: LOOP
SET #filter_month = SPLIT_STR(filter_range, ',', #counter);
IF #filter_month = '' THEN LEAVE filters;
ELSE
INSERT INTO filter_months (filter_month) VALUES (#filter_month);
SET #counter = #counter + 1;
END IF;
END LOOP;
SELECT COUNT(*) INTO #matches FROM months_between_dates INNER JOIN filter_months ON months_between_dates.month_stuff = filter_months.filter_month;
IF #matches >= 1 THEN RETURN 1;
ELSE RETURN 0;
END//
DELIMITER ;
drop table statements cause an implicit commit, which is not allowed in a mysql function. drop temporary table doesn't cause the commit though. if you're not worried about regular (non-temporary) tables named months_between_dates or filter_months existing you should be able to change
DROP TABLE IF EXISTS months_between_dates;
DROP TABLE IF EXISTS filter_months;
to
DROP TEMPORARY TABLE IF EXISTS months_between_dates;
DROP TEMPORARY TABLE IF EXISTS filter_months;