MySQL UDF / Stored函数无法识别作为参数传递的表名

时间:2017-01-20 01:56:59

标签: mysql function parameter-passing

以下是存储的功能:

DELIMITER //
CREATE FUNCTION `calcMedian`(
    `tbl` VARCHAR(64),
    `clm` VARCHAR(64)
) RETURNS decimal(14,4)
BEGIN

    SELECT AVG(middle_values) AS 'median'
    INTO medRslt
    FROM (
        SELECT t1.clm AS 'middle_values'
        FROM
        (
            SELECT @row:=@row+1 as `row`, table_column_name
            FROM tbl, (SELECT @row:=0) AS r
            ORDER BY clm
        ) AS t1,
        (
            SELECT COUNT(*) as 'count'
            FROM tbl        
        ) AS t2

        WHERE t1.row >= t2.count/2 and t1.row <= ((t2.count/2) +1)) AS t3;  
    RETURN medRslt; 
END//
DELIMITER ;

然后我继续执行以下查询:

USE ap2;

SELECT vendor_id, calcMedian('invoices', 'invoice_total')
FROM invoices i
WHERE vendor_id = 97
GROUP BY vendor_id;

我收到错误消息:

SQL Error (1146): Table 'ap2.tbl' doesn't exist *

我理解以下内容可能比存储过程/预处理语句更好,而不是函数。我现在只想一步一步地做事。

我还做了一个不同的功能,只需输出存储在变量&#39; tbl&#39;中的值,它显示正确的表名(在这种情况下是发票)。

1 个答案:

答案 0 :(得分:2)

SQL语句中的标识符不能作为值提供。必须在SQL文本中指定标识符(表名,列名,函数名等)。

要获取在过程中的SQL语句中用作表名的tbl变量(过程参数)的值,可以使用动态SQL

将变量设置为SQL文本,合并字符串值,然后将该字符串作为SQL语句执行。举个例子:

  SET @sql = CONCAT( 'SELECT AVG(middle_values) AS `median`'
                   , ' INTO medRslt'
                   , ' ... '
                   , tbl
                   , ' ... '
             );
  PREPARE stmt FROM @sql;
  EXECUTE stmt;
  DEALLOCATE PREPARE stmt;

请注意,将字符串值合并到SQL文本中会使该过程受到SQL注入漏洞的影响。

如果我必须这样做,我会通过验证tbl不包含反引号字符来减少SQL注入的可能性,并在反引号中包含/转义标识符,例如。

   CONCAT( ' ...' , '`' , tbl , '`' , ' ... ' );
                    ^^^         ^^^