以下是存储的功能:
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;中的值,它显示正确的表名(在这种情况下是发票)。
答案 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 , '`' , ' ... ' );
^^^ ^^^