在LIMIT子句中使用一个设置的变量

huangapple go评论91阅读模式
英文:

Using a set variable inside the LIMIT clause

问题

我试图从一行中选择前50%的数据。我正在这样做的方式是首先计算行中有多少元素,然后将其除以2,然后将该结果用于LIMIT子句。

SET @UPPER := (SELECT ROUND(COUNT(LONG_W)/2) FROM STATION);
SELECT LONG_W FROM STATION ORDER BY LONG_W DESC LIMIT @UPPER;

我在Hackerrank网站上进行这个操作,我已经选择了MySQL方言。

如果我执行 Select @UPPER; 我会得到预期的结果,在这种情况下是250。如果我只写 LIMIT 250 它也可以工作,但我正在尝试使用变量,因为我不能总是知道确切的中间值。

目前遇到以下错误:

错误 1064 (42000) 第6行: SQL语法错误; 请检查与您的MySQL服务器版本相对应的手册,以了解在第1行附近使用'@UPPER'的正确语法。

我已经检查确保变量包含正确的值,并手动使用该值来检查是否得到预期的结果。

英文:

I'm trying to select the top 50% from a row. The way I'm doing it is by first calculating how many elememts there are in the row, dividing by 2, then using that result inside the LIMIT clause.

SET @UPPER := (SELECT ROUND(COUNT(LONG_W)/2) FROM STATION);
SELECT LONG_W FROM STATION ORDER BY LONG_W DESC LIMIT @UPPER;

I'm doing it in the Hackerrank website, and I do have selected the MySQL dialect.

If I do Select @UPPER; I am getting the expected result, 250 in this case. If I simply write LIMIT 250 it does work, but I'm trying to do it with the variable since I can't always expect to know what is the exact middle.

Currently getting the following error:

> ERROR 1064 (42000) at line 6: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '@UPPER' at line 1.

I've check to make sure the variable holds the right value and I've manually used that value to check if I get the expected result.

答案1

得分: 1

LIMIT子句内无法使用变量。根据MySQL官方文档

LIMIT接受一个或两个数字参数,这两个参数必须都是非负整数常数,但有以下例外情况:

  • 在预备语句中,可以使用?占位符来指定LIMIT参数。
  • 在存储过程中,可以使用整数值例程参数或本地变量来指定LIMIT参数。

根据文档的建议,你只能使用预备语句(具有动态查询)或存储程序来实现这一点。

动态查询容易受到SQL注入的影响。如果你认为这可能与你的用例有关,你可以在存储过程中执行动态查询,以强制输入的强类型化。

英文:

You can't use variables within the LIMIT clause. As per MySQL official documentation:

>LIMIT takes one or two numeric arguments, which must both be nonnegative integer constants, with these exceptions:
> * Within prepared statements, LIMIT parameters can be specified using ? placeholder markers.
> * Within stored programs, LIMIT parameters can be specified using integer-valued routine parameters or local variables.

As suggested by the doc, you can only achieve this using a prepared statement (with a dynamic query) or a stored program.

SET @UPPER := (SELECT ROUND(COUNT(LONG_W)/2) 
               FROM STATION);

SET @sql := CONCAT('SELECT LONG_W 
                    FROM STATION 
                    ORDER BY LONG_W DESC 
                    LIMIT ', @UPPER);
                   
PREPARE stmt FROM @sql;

EXECUTE stmt;

DEALLOCATE PREPARE stmt;

Check the demo here.


Dynamic querying is prone to SQL injection. If you feel this may be a relevant problem to your use case, you can execute your dynamic query within a stored procedure, to enforce strong typization of inputs.

SET @UPPER := (SELECT ROUND(COUNT(LONG_W)/2) FROM STATION);

DELIMITER //

CREATE PROCEDURE generate_sample_stations(
  	IN num_stations INT
)
BEGIN
	SET @num_stations = num_stations;

	PREPARE stmt FROM 'SELECT LONG_W 
                       FROM STATION 
                       ORDER BY LONG_W DESC 
                       LIMIT ?';
	
    EXECUTE stmt USING @num_stations;
    
    DEALLOCATE PREPARE stmt;
END//

DELIMITER ;

CALL generate_sample_stations(@UPPER);

Check the demo here.

Note: If you can avoid using variables for your LIMIT clause at all, it's better in the far end.

huangapple
  • 本文由 发表于 2023年3月9日 19:49:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/75684203.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定