Mysql procedure to modify limit and offset - mysql

Just a thought in my mind but would it not be possible to createa function in MySQL that can modify the LIMIT within a query
The clause would be a simple calculation function that would work out the offset depending on the pageno * perpage
Example
SELECT * FROM items PAGE(4,20)
this would be the same as
SELECT * FROM items LIMIT 100,20
I have never created any procedures before so the below would be wrong..
CREATE PROCEDURE (int pagno, int limit)
BEGIN
ofsset = roundup(pageno * limit)
END
But within that query actually set the limit and offset for the query?

you can do something like this ofc:
drop procedure if exists foo;
delimiter #
create procedure foo
(
in p_limit int unsigned
)
proc_main:begin
set SQL_SELECT_LIMIT = p_limit;
select * from <table>...
set SQL_SELECT_LIMIT = DEFAULT;
end proc_main #
delimiter ;
call foo(64);

Related

MYSQL - table not updating from Procedure

I want to get distance between two GeoPoints (using LatLong) for that I wrote GETDISTANCE function from solution provided [MySQL Function to calculate distance between two latitudes and longitudes. If I call function independently it works like charm.
As per my understanding I cannot return ResultSet from Function in MySQL so I created Procedure and called function inside procedure As follows:
DELIMITER $$
CREATE PROCEDURE GetNearByGeoPoints(IN Lat REAL, IN Longi REAL)
BEGIN
DECLARE v_max int;
DECLARE v_counter int unsigned default 0;
SET #v_max = (SELECT COUNT(*) FROM TransmitterPointsData);
START TRANSACTION;
WHILE v_counter < v_max
DO
SELECT #coverageID :=CoverageID, #tableLatitude := Latitude, #tableLongitude :=Longitude FROM TransmitterPointsData LIMIT v_counter,1;
SET #Dist= GETDISTANCE(Lat, Longi, tableLatitude, tableLongitude);
UPDATE TransmitterPointsData SET DynamicDistance = #Dist WHERE CoverageID= #coverageID;
set v_counter=v_counter+1;
END WHILE;
COMMIT;
SELECT * FROM TransmitterPointsData;
END $$
DELIMITER ;
What I am trying to do is taking a set of LatLong parameters from user and comparing it with each set of LatLong from table. And after getting output from function I am updating TransmitterPointsData table with where condition on coverageID.
This is my first MySQL query so far I was following syntax but I do not know why I am getting all null values in DynammicDistance Column.
Thank You in Advance
Try replacing the while loop with this:
UPDATE TransmitterPointsData
SET DynamicDistance = GETDISTANCE(Lat, Longi, Latitude, Longitude)
Much shorter, and you avoid potential issues with row selection via limit + offset (which is poor style at best, and gives you a random row each time at worse).

How can I populate a test table in MySQL with one billion rows?

I want to do some tests with MySQL indexes and would like to see the effects of the different types of indexes (covering, clustering) on different queries myself by experimenting.
I have a very simple table with 3 cols, a, b, c.
DROP TABLE IF EXISTS test_table;
CREATE TABLE IF NOT EXISTS test_table (
a INT UNSIGNED NOT NULL,
b INT UNSIGNED NOT NULL,
c INT UNSIGNED NOT NULL
);
I then created a stored procedure to populate this 1000 times with random values from 1 to 100.
DROP PROCEDURE IF EXISTS test_procedure;
DELIMITER //
CREATE PROCEDURE test_procedure
(IN loop_amount INT)
BEGIN
DECLARE rand_max INT DEFAULT 99;
DECLARE a, b, c INT;
DECLARE i INT DEFAULT 0;
TRUNCATE TABLE test_table;
WHILE i < loop_amount DO
SET a = RAND() * rand_max + 1;
SET b = RAND() * rand_max + 1;
SET c = RAND() * rand_max + 1;
INSERT INTO test_table VALUES (a, b, c);
SET i = i + 1;
END WHILE;
END //
DELIMITER ;
CALL test_procedure(1000);
I could not run this many times because it became slow after 1000 loops.
I then doubled the table 13 times.
DROP PROCEDURE IF EXISTS test_procedure;
DELIMITER //
CREATE PROCEDURE test_procedure
(IN loop_amount INT)
BEGIN
DECLARE i INT DEFAULT 0;
WHILE i < loop_amount DO
INSERT INTO test_table SELECT * FROM test_table;
SET i = i + 1;
END WHILE;
END //
DELIMITER ;
CALL test_procedure(13);
But now it has around 16 million rows but I can't run this function anymore because it takes like a minute to run it with 1 as parameter, doubling once takes a minute, next doubling takes 2 minutes etc. How can I get to 1 billion faster?
Also the SELECT COUNT(*) FROM test_table; is really slow too. How can I speed this up to confirm table size?
load data local infile 'c:\a.txt' into table test_table;
[SQL]
load data local infile 'c:\a.txt' into table test_table;
受影响的行: 1000000
时间: 12.177s

Error creating MYSQL function to work out time diff

I am creating a function as part of a database project with a group at university. I want the function to return the fastest time a race was complete in and have tried the following code. I am getting an error as I think it is trying to return more than one value but cannot think of another way to do this. Any help is appreciated.
DELIMITER //
CREATE OR REPLACE FUNCTION calc_race_winner(in_race_id INT)
RETURNS FLOAT(10)
BEGIN
CREATE TEMPORARY TABLE IF NOT EXISTS temp_result AS (
SELECT
(TIME_TO_SEC(TIMEDIFF(ps_result.finish_time, ps_race.start_time)) / 60) AS finish_time_mins
FROM ps_race
INNER JOIN ps_result ON ps_race.race_id = ps_result.race_id
);
SELECT *
FROM temp_result
WHERE ps_race.race_id = in_race_id
ORDER BY finish_time_mins ASC LIMIT 1;
RETURN finish_time_mins;
END//
DELIMITER ;
Define a local variable to read finish time into it and return the same.
begin
declare finish_time_calculated_in_mins int default 0;
create temp.....
....
select finish_time_mins
into finish_time_calculated_in_mins
from temp_result
where ps_race.race_id = in_race_id
order by finish_time_mins asc
limit 1;
return finish_time_calculated_in_mins;
end;

Creating MySQL Temporary Table then Assign CRUD From It

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.

Using variable in a LIMIT clause in MySQL

I am writing a stored procedure where I have an input parameter called my_size that is an INTEGER. I want to be able to use it in a LIMIT clause in a SELECT statement. Apparently this is not supported, is there a way to work around this?
# I want something like:
SELECT * FROM some_table LIMIT my_size;
# Instead of hardcoding a permanent limit:
SELECT * FROM some_table LIMIT 100;
For those, who cannot use MySQL 5.5.6+ and don't want to write a stored procedure, there is another variant. We can add where clause on a subselect with ROWNUM.
SET #limit = 10;
SELECT * FROM (
SELECT instances.*,
#rownum := #rownum + 1 AS rank
FROM instances,
(SELECT #rownum := 0) r
) d WHERE rank < #limit;
STORED PROCEDURE
DELIMITER $
CREATE PROCEDURE get_users(page_from INT, page_size INT)
BEGIN
SET #_page_from = page_from;
SET #_page_size = page_size;
PREPARE stmt FROM "select u.user_id, u.firstname, u.lastname from users u limit ?, ?;";
EXECUTE stmt USING #_page_from, #_page_size;
DEALLOCATE PREPARE stmt;
END$
DELIMITER ;
USAGE
In the following example it retrieves 10 records each time by providing start as 1 and 11. 1 and 11 could be your page number received as GET/POST parameter from pagination.
call get_users(1, 10);
call get_users(11, 10);
A search turned up this article. I've pasted the relevant text below.
Here's a forum post showing an example of prepared statements letting
you assign a variable value to the limit clause:
http://forums.mysql.com/read.php?98,126379,133966#msg-133966
However, I think this bug should get some attention because I can't
imagine that prepared statements within a procedure will allow for any
procedure-compile-time optimizations. I have a feeling that prepared
statements are compiled and executed at the runtime of the procedure,
which probaby has a negative impact on efficiency. If the limit
clause could accept normal procedure variables (say, a procedure
argument), then the database could still perform compile-time
optimizations on the rest of the query, within the procedure. This
would likely yield faster execution of the procedure. I'm no expert
though.
I know this answer has come late, but try SQL_SELECT_LIMIT.
Example:
Declare rowCount int;
Set rowCount = 100;
Set SQL_SELECT_LIMIT = rowCount;
Select blah blah
Set SQL_SELECT_LIMIT = Default;
This feature has been added to MySQL 5.5.6.
Check this link out.
I've upgraded to MySQL 5.5 just for this feature and works great.
5.5 also has a lot of performance upgrades in place and I totally recommend it.
Another way, the same as wrote "Pradeep Sanjaya", but using CONCAT:
CREATE PROCEDURE `some_func`(startIndex INT, countNum INT)
READS SQL DATA
COMMENT 'example'
BEGIN
SET #asd = CONCAT('SELECT `id` FROM `table` LIMIT ',startIndex,',',countNum);
PREPARE zxc FROM #asd;
EXECUTE zxc;
END;
As of MySQL version 5.5.6, you can specify LIMIT and OFFSET with variables / parameters.
For reference, see the 5.5 Manual, the 5.6 Manual and #Quassnoi's answer
I've faced the same problem using MySql 5.0 and wrote a procedure with the help of #ENargit's answer:
CREATE PROCEDURE SOME_PROCEDURE_NAME(IN _length INT, IN _start INT)
BEGIN
SET _start = (SELECT COALESCE(_start, 0));
SET _length = (SELECT COALESCE(_length, 999999)); -- USING ~0 GIVES OUT OF RANGE ERROR
SET #row_num_personalized_variable = 0;
SELECT
*,
#row_num_personalized_variable AS records_total
FROM(
SELECT
*,
(#row_num_personalized_variable := #row_num_personalized_variable + 1) AS row_num
FROM some_table
) tb
WHERE row_num > _start AND row_num <= (_start + _length);
END;
Also included the total rows obtained by the query with records_total.
you must DECLARE a variable and after that set it. then the LIMIt will work and put it in a StoredProcedure not sure if it works in normal query
like this:
DECLARE rowsNr INT DEFAULT 0;
SET rowsNr = 15;
SELECT * FROM Table WHERE ... LIMIT rowsNr;