1

I am working on a stored procedure in mariadb and I try to dynamically limit the number of rows. If I hardcode the Limit e.g. LIMIT 5 my procedure works perfectly but if I write LIMIT @below it I receive a quite generic sql syntax error. I can use the variable @below everywhere else in my statement but not after LIMIT. Would be nice to understand this behavior?

SET sql_mode=ORACLE; 
CREATE PROCEDURE hello AS 
BEGIN
DECLARE
below INT;
BEGIN
SELECT round(COUNT(*)/2) FROM tableName INTO @below;

SELECT 
col1,col2, col3, @below /* this is ok*/
FROM tableName 
WHERE col1=@below /* this is ok*/
LIMIT @below; /* doesn't work*/
END;
END hello;

I receive this error:

SQL ERROR(1064): You have an error in your SQL syntax check the manual that corresponds to your MariaDB server version for the right syntax to use near '@below

Thanks Amit

Amit
  • 126
  • 2
  • 10
  • I removed the Oracle tag, since this question doesn't seem to be related to Oracle. – The Impaler Mar 03 '21 at 17:36
  • What's the error? – The Impaler Mar 03 '21 at 17:37
  • Well... that's pretty common. I've seen the same error in DB2. The engine only accepts parameters at specific locations in the SQL statement. It seems that `LIMIT` is not one of them for this particular version of the engine. The typical solution is to use Dynamic SQL: that is, to assemble the query inside the procedure and then run it, instead of have it prepared already (as you wanted). – The Impaler Mar 03 '21 at 17:38
  • @Impaler, I edited the question. – Amit Mar 03 '21 at 18:02
  • It seems it's not possible (as of this version of MariaDB) to use a parameter in that specific location of the query. You'll need to assemble the query dynamically. See https://stackoverflow.com/questions/23178816/mysql-dynamic-query-in-stored-procedure. – The Impaler Mar 03 '21 at 18:04

2 Answers2

1

You can achieve this with row_number()over() :

select col1,col2,col3 from(
SELECT 
col1,col2, col3, row_number()over(order by (select 1)) rownumber
FROM tableName ) 
where rownumber<= @below; 
1

Dynamic query can help here:

SET sql_mode=ORACLE; 
CREATE PROCEDURE hello AS 
BEGIN
DECLARE
below INT;
BEGIN
    SELECT ROUND(COUNT(*)/2) FROM tableName INTO @below;
    SET @query = CONCAT('SELECT col1,col2, col3, ? FROM tableName WHERE col1= ? LIMIT ', @below);
    
    PREPARE stmt FROM @query;
    EXECUTE stmt USING @below, @below;
    
    DEALLOCATE PREPARE stmt;
END;
END hello;
Slava Rozhnev
  • 9,510
  • 6
  • 23
  • 39
  • Thanks, this approach works for me if I just do 'EXECUTE stmt;' instead 'EXECUTE stmt USING @below, @below;' – Amit Mar 05 '21 at 13:35