存储函数中动态 sql 的替代方法

Alternatives to dynamic sql in stored function

我正在编写一个存储函数,用于计算单元格的位置,我需要从 table 中 select 计算该值。为此,我决定将这个位置保存在一个变量中,以便将其用作 LIMIT 子句的偏移量。

根据我的研究,通过 LIMIT 语句将值设置为局部变量的方式是通过准备语句,但我也得到了允许在存储中使用准备语句(也不是任何动态 SQL)职能。有没有其他方法可以解决我的问题?

我的情况的简化示例:

CREATE FUNCTION foo(a int) RETURNS decimal DETERMINISTIC
BEGIN
     SET @var1 := (SELECT COUNT(*) FROM table);
     SET @var2 := (ROUND(@var1 * a/5))
     PREPARE STMT FROM 'RETURN (SELECT * FROM other_table LIMIT ?, ?)';
     EXECUTE STMT USING @var2, @var1;
END
$$ DELIMITER ;

理想情况下,这会让我在需要的地方得到我需要的结果。但是,当然,我收到错误代码 1336 说 "Dynamic SQL is not allowed in stored function or trigger"

此存储函数不需要动态 SQL。您不需要为 LIMIT 子句使用动态 SQL。您只需要确保变量是 INT 类型,而不是字符串。

这是一个快速演示:

create function foo(a int) returns int reads sql data 
begin 
  return (select x from test limit 1 offset a); 
end

注意其他几件事:

  • 使用 READS SQL DATA 而不是 DETERMINISTIC。您的功能不是确定性的。您应该阅读创建函数的手册页以更好地理解这些选项。
  • 不要使用 SELECT *。一个函数只能 return 一个标量值,而不是一组列。您查询的table实际上可能只有一列,但是让查询更清楚是个好习惯。
  • 使用 LIMIT 而不使用 ORDER BY 以后可能会让您感到惊讶,因为它不能保证将使用哪个顺序来确定偏移量。最好明确使用 ORDER BY
  • 使用LIMIT时,我觉得用LIMIT <count> OFFSET <offset>LIMIT <offset>, <count>更清楚。他们做同样的事情,但更容易记住哪个论点是哪个。
  • 您的 LIMIT 查询似乎 select 有很多行。您需要查询 select 恰好是一列和一行,否则它对来自存储函数的 return 无效。