use*_*443 5 mysql dynamic-sql prepared-statement
我整理了一个简单的存储过程,在其中传递了两个参数以使其更具动态性。我已经在“前两位数和记录数”部分中准备了一条语句来完成此操作。
我不确定的是是否可以通过SET vTotalFT
准备好的语句使该部分动态化。
目前,我必须对表名和字段进行硬编码。我希望vTotalFT
基于准备好的动态SQL语句分配变量,但是我不确定语法。想法是,当我调用过程时,可以告诉它要用于分析的表和字段。
CREATE PROCEDURE `sp_benfords_ft_digits_analysis`(vTable varchar(255), vField varchar(255))
SQL SECURITY INVOKER
BEGIN
-- Variables
DECLARE vTotalFT int(11);
-- Removes existing table
DROP TABLE IF EXISTS analysis_benfords_ft_digits;
-- Builds base analysis table
CREATE TABLE analysis_benfords_ft_digits
(
ID int(11) NOT NULL AUTO_INCREMENT,
FT_Digits int(11),
Count_of_Records int(11),
Actual decimal(18,3),
Benfords decimal(18,3),
Difference Decimal(18,3),
AbsDiff decimal(18,3),
Zstat decimal(18,3),
PRIMARY KEY (ID),
KEY id_id (ID)
);
-- First Two Digits and Count of Records
SET @s = concat('INSERT INTO analysis_benfords_ft_digits
(FT_Digits,Count_of_Records)
select substring(cast(',vField,' as char(50)),1,2) as FT_Digits, count(*) as Count_of_Records
from ',vTable,'
where ',vField,' >= 10
group by 1');
prepare stmt from @s;
execute stmt;
deallocate prepare stmt;
SET vTotalFT = (select sum(Count_of_Records) from
(select substring(cast(Gross_Amount as char(50)),1,2) as FT_Digits, count(*) as Count_of_Records
from supplier_invoice_headers
where Gross_Amount >= 10
group by 1) a);
-- Actual
UPDATE analysis_benfords_ft_digits
SET Actual = Count_of_Records / vTotalFT;
-- Benfords
UPDATE analysis_benfords_ft_digits
SET Benfords = Log(1 + (1 / FT_Digits)) / Log(10);
-- Difference
UPDATE analysis_benfords_ft_digits
SET Difference = Actual - Benfords;
-- AbsDiff
UPDATE analysis_benfords_ft_digits
SET AbsDiff = abs(Difference);
-- ZStat
UPDATE analysis_benfords_ft_digits
SET ZStat = cast((ABS(Actual-Benfords)-IF((1/(2*vTotalFT))<ABS(Actual-Benfords),(1/(2*vTotalFT)),0))/(SQRT(Benfords*(1-Benfords)/vTotalFT)) as decimal(18,3));
Run Code Online (Sandbox Code Playgroud)
首先,要使用动态表/列名称,您需要像第一次查询一样使用字符串/ 准备语句@s
。接下来,要从COUNT()
查询内部获取返回值,您将需要使用SELECT .. INTO @vTotalFT
。
以下是您所需要的:
SET @vTotalFTquery = CONCAT('(select sum(Count_of_Records) INTO @vTotalFT from
(select substring(cast(', vField, ' as char(50)),1,2) as FT_Digits, count(*) as Count_of_Records
from ', vTable, '
where ', vField, ' >= 10
group by 1) a);');
PREPARE stmt FROM @vTotalFTquery;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
Run Code Online (Sandbox Code Playgroud)
请注意:变量名称已从更改vTotalFT
为@vTotalFT
。如果没有,它似乎无法工作@
。而且,在@vTotalFT
查询之外/之前声明该变量时,该变量将不起作用,因此,如果遇到错误或空结果可能是原因。