MySQL(存储)过程 - 参数和查询

Posted

技术标签:

【中文标题】MySQL(存储)过程 - 参数和查询【英文标题】:MySQL (Stored) Procedure - parameters and query 【发布时间】:2013-10-10 12:19:20 【问题描述】:

我正在尝试创建一个带参数的简单过程。

CALL new_procedure('mode', 'ASC');

第一个输入是列,第二个是排序方向

DELIMITER $$

CREATE DEFINER=`root`@`localhost` PROCEDURE `new_procedure`(IN in_order_by_column varchar(20), in_order_by_direction char(4))
BEGIN

    DECLARE order_by varchar(30);
    SET @order_by = CONCAT('`', in_order_by_column, '` ', in_order_by_direction);
/*
    SELECT * FROM `common_tags` ORDER BY @order_by  LIMIT 5;
*/
    SELECT @order_by as 'c';

END

在上面的例子中,我只输出了 2 个参数,所以我可以看到发生了什么。

结果:

"c"
`mode` ASC

.

当我使用预期代码运行该过程时,如下所示。

DELIMITER $$

CREATE DEFINER=`root`@`localhost` PROCEDURE `new_procedure`(IN in_order_by_column varchar(20), in_order_by_direction char(4))
BEGIN

    DECLARE order_by varchar(30);
    SET @order_by = CONCAT('`', in_order_by_column, '` ', in_order_by_direction);
    SELECT * FROM `common_tags` ORDER BY @order_by  LIMIT 5;

END

结果

tags_id     data                mode        parent_id       position
1           Wood                2           13              6
2           Trippy              0           0               0
4           Artists             1           0               1
6           "Newest Additions"  1           0               11
12          "Natural Elements"  2           5               8

如您所见,结果未按mode 排序。

感谢任何帮助。

【问题讨论】:

【参考方案1】:

很遗憾,在这种情况下,您需要PREPARE 整个查询:

DELIMITER $$

DROP PROCEDURE IF EXISTS `new_procedure`$$

CREATE PROCEDURE `new_procedure`(IN in_order_by_column varchar(20), in_order_by_direction char(4))
BEGIN
    SET @buffer = CONCAT_WS('',
        'SELECT * FROM `common_tags` ORDER BY `', in_order_by_column, '` ', in_order_by_direction, ' LIMIT 5'
    );

    PREPARE stmt FROM @buffer;
    EXECUTE stmt;

    DEALLOCATE PREPARE stmt;
END$$

DELIMITER ;

注意:非常小心使用所描述的方法,因为如果使用不当,很容易受到 SQL 注入攻击。

【讨论】:

您可能希望使用quote() 引用输入值,请参阅dev.mysql.com/doc/refman/8.0/en/… @Leukipp OP 正在尝试使用不同的列和方向来构建查询。您建议的函数旨在转义值,而不是用于列、方向或任何查询描述部分。 我的评论提到了您关于构造查询易受 SQL 注入攻击的注释。 澄清@Leukipp的建议:这个特定的构造查询只使用参数作为列名SQL关键字 - 使用quote()会导致错误。就像 BlitZ 一样,通过用反引号包围列名来保护列名不被注入。 Leukipp 的评论对于将这种技术用于查询中作为 values 的参数的任何人来说确实很有用(因此在不同的 concat'd 查询中对我很有用,以避免 SQL 注入)。 关于 SQL 注入的更多信息:in_order_by_direction 不受保护;更好的方法是传入一个经过测试的布尔值,在 CONCAT 查询时替换为 ASCDESC。为了安全起见,查询的每个部分都必须通过某种方式加以保护。

以上是关于MySQL(存储)过程 - 参数和查询的主要内容,如果未能解决你的问题,请参考以下文章

mysql 存储过程分页 转载

怎么在mysql中查询已建立的存储过程

mysql存储过程实例,查询多参数赋值

mysql存储过程实现数据查询与插入

MySQL存储过程

将日期作为 MySQL 存储过程的 IN 参数处理