63

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;
5
  • If you have control over which version of MySQL you use, it looks like this is fixed starting in v5.5.6. bugs.mysql.com/bug.php?id=11918 Commented Aug 13, 2011 at 16:57
  • found another simple solution stackoverflow.com/a/4315661 Commented Nov 20, 2013 at 6:20
  • 6
    Note that in MySQL 5.7.16 (and maybe others) the LIMIT @nrows OFFSET @noffset in a stored routine seems to be rejected too, while a LIMIT nrows OFFSET noffset is accepted, as long as you DECLARE nrows INT; DECLARE noffset INT at the routine's begining. Commented May 18, 2017 at 8:04
  • @Xenos It didnt work in big query, do you know how to make it work in big query Commented Jun 2, 2021 at 12:47
  • @VarunKumar Share your query in a dedicated question if you need help, as I don't see any reason why this would not work for "big" query Commented Jun 3, 2021 at 15:05

10 Answers 10

33

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;
Sign up to request clarification or add additional context in comments.

Comments

17

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);

Comments

16

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;

2 Comments

Unfortunately doesn't seem to support an argument for starting position, like 5,2 for taking 2 rows from position 5. But unless you need that it may do the trick.
Also unfortunately this trick doesn't work for a SELECT ... part of queries such as REPLACE ... SELECT ....
15

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.

Comments

13

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.

Comments

3

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;

1 Comment

It is great solution with using PREPARE and EXECUTE statement. One important note : we don't need to use Create procedure. We can use PREPARE**and **EXECUTE statement in major code sql too.
1

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

Comments

1

It seems that many people here want to use LIMIT as a parameter without stored procedures.

it can be done with PREPARE and EXECUTE like this:

set @my_size = 100;
set @sql = concat("SELECT * FROM some_table LIMIT ", @my_size);
PREPARE stmt FROM @sql;
EXECUTE stmt;

Comments

0

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.

Comments

-1

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;

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.