Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/71.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mysql 如何在存储过程中使用准备好的语句分配变量?_Mysql_Prepared Statement_Dynamic Sql - Fatal编程技术网

Mysql 如何在存储过程中使用准备好的语句分配变量?

Mysql 如何在存储过程中使用准备好的语句分配变量?,mysql,prepared-statement,dynamic-sql,Mysql,Prepared Statement,Dynamic Sql,我已经组合了一个简单的存储过程,其中传递了两个参数以使其更具动态性。我已经在前两位数字和记录计数部分准备好了语句 我不确定的是,我是否也可以使用一个准备好的语句使setvtotalft部分动态 目前,我必须硬编码表名和字段。我希望根据准备好的动态SQL语句分配vTotalFT变量,但我不确定语法。这个想法是,当我调用我的过程时,我可以告诉它使用哪个表和哪个字段进行分析 CREATE PROCEDURE `sp_benfords_ft_digits_analysis`(vTable varchar

我已经组合了一个简单的存储过程,其中传递了两个参数以使其更具动态性。我已经在前两位数字和记录计数部分准备好了语句

我不确定的是,我是否也可以使用一个准备好的语句使setvtotalft部分动态

目前,我必须硬编码表名和字段。我希望根据准备好的动态SQL语句分配vTotalFT变量,但我不确定语法。这个想法是,当我调用我的过程时,我可以告诉它使用哪个表和哪个字段进行分析

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));

首先,要使用动态表/列名,您需要使用字符串/就像您对@s的第一次查询一样。接下来,要从查询内部的COUNT中获取返回值,需要使用

以下是您所需的全部内容:

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;

请注意:变量名已从vTotalFT更改为@vTotalFT。没有@它似乎不起作用。此外,如果在查询之外/之前声明变量@vTotalFT,则该变量将不起作用,因此如果遇到错误或空结果,则可能是原因。

谢谢。我星期一试试这个。干杯这里有一个严重的问题,使用预处理语句的全部目的是清理用户输入,但是您盲目地将vTable和vField连接到select语句中。这个答案可以接受SQL注入。@Coderer虽然我大体上同意你的说法,但我相信你误解了问题/答案的意图。问题是如何动态插入表名和列名——这两者都不能通过预先准备好的语句来替换。也就是说,我的答案是针对OP的how to,而不是附带的答案,这是一个直接在MySQL中正确清理表/列名的步骤列表。如果您认为我的答案仍然不正确,请随意编辑以使其更合适,或添加您自己的答案以说明您的观点=]这是一个好观点-不幸的是,我不知道您如何以安全的方式做到这一点。我能想到的最接近的方法是将输入参数限制为尽可能少的字符,以减少攻击者可能注入的代码量。例如,如果您的所有列和表名都少于(比如)10个字符,那么这可能非常安全。@Coderer不要吹毛求疵,但您已经给出了我的答案a-1,因为您觉得回答所问的问题没有用。你的推理基于一个你自己无法立即回答的旁题。当你在未来投票时,请考虑在你的推理中提出的实际问题,而不仅仅是你个人的要求。同样的,如果你觉得像我这样的答案需要更多的信息,请随时留下评论。
SELECT CONCAT (
        'SELECT DATE(PunchDateTime) as day , '
        ,GROUP_CONCAT('GROUP_CONCAT(IF(PunchEvent=', QUOTE(PunchEvent), ',PunchDateTime,NULL))
       AS `', REPLACE(PunchEvent, '`', '``'), '`')
        ,'
         FROM     tbl_punch
         GROUP BY DATE(PunchDateTime) 
         ORDER BY PunchDateTime ASC
       '
        )
INTO @sql
FROM (
    SELECT DISTINCT PunchEvent
    FROM tbl_punch
    ) t;

PREPARE stmt
FROM @sql;

EXECUTE stmt;

DEALLOCATE PREPARE stmt;