英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论