【问题标题】:mysql procedure - issue with parsing parameter in where condition in clausemysql过程-在where条件子句中解析参数的问题
【发布时间】:2016-08-03 13:45:10
【问题描述】:

下面是过程

CREATE DEFINER=`root`@`localhost` PROCEDURE `sitter_price`(
   in in_hours float,
   in age varchar(100),
   in no_of_sitters int,
   in no_of_days int
)
BEGIN
  select 
  TRUNCATE(sum(price)*in_hours*no_of_days*no_of_sitters,2) as 
  total_amount 
    from job_prices jp
    join kids_ages ka on ka.id = jp.kids_age_id
where ka.age in(age) and start_hours > in_hours 
    AND in_hours <= end_hours;
END

这个过程的问题是我将如何传入age varchar(100), parameter in, in 子句 目前我正在使用查询进行解析

CALL `usitterz`.`sitter_price`(4.10,'1,2,3,4', 3, 5);

但这是错误的,因为在查询中像 in('1,2,3,4') 一样读取它,但我希望它像 - in(1,2,3,4)。

会是这样的

CREATE DEFINER=`root`@`localhost` PROCEDURE `sitter_price`(
   in in_hours float,
   in age varchar(100),
   in no_of_sitters int,
   in no_of_days int
)
BEGIN
  select 
  TRUNCATE(sum(price)*in_hours*no_of_days*no_of_sitters,2) as 
  total_amount 
    from job_prices jp
    join kids_ages ka on ka.id = jp.kids_age_id
where ka.age in(1,2,3,4) and start_hours > in_hours 
    AND in_hours <= end_hours;
END

【问题讨论】:

    标签: mysql stored-procedures


    【解决方案1】:

    第 1 步:四处寻找适合 EXECUTE 的字符串

    DROP PROCEDURE IF EXISTS sitter_price;
    DELIMITER $
    CREATE DEFINER=`root`@`localhost` PROCEDURE `sitter_price`(
       in in_hours float,
       in age varchar(100),
       in no_of_sitters int,
       in no_of_days int
    )
    BEGIN
        SET @theSql=CONCAT('SELECT TRUNCATE(sum(price)*',in_hours,'*',no_of_days,'*',no_of_sitters,',2)');
        SET @theSql=CONCAT(@theSql,' as total_amount from job_prices jp join kids_ages ka on ka.id = jp.kids_age_id');
        SET @theSql=CONCAT(@theSql,' where ka.age in(',age,') and start_hours > ',in_hours,' AND ');
        SET @theSql=CONCAT(@theSql,in_hours,'<= end_hours');
        /*
      select 
      TRUNCATE(sum(price)*in_hours*no_of_days*no_of_sitters,2) as 
      total_amount 
        from job_prices jp
        join kids_ages ka on ka.id = jp.kids_age_id
    where ka.age in(1,2,3,4) and start_hours > in_hours 
        AND in_hours <= end_hours;
        */
        select @theSql;
    END$
    DELIMITER ;
    

    Step2:传入参数看看字符串是什么样子的

    call sitter_price(89,'1,2,4,8',11,12);
    
    SELECT TRUNCATE(sum(price)*89*12*11,2) as total_amount 
    from job_prices jp 
    join kids_ages ka on ka.id = jp.kids_age_id 
    where ka.age in(1,2,4,8) and start_hours > 89 
    AND 89<= end_hours
    

    第 3 步:使用 PREPAREEXECUTE 完成存储过程。

    DROP PROCEDURE IF EXISTS sitter_price;
    DELIMITER $
    CREATE DEFINER=`root`@`localhost` PROCEDURE `sitter_price`(
       in in_hours float,
       in age varchar(100),
       in no_of_sitters int,
       in no_of_days int
    )
    BEGIN
        SET @theSql=CONCAT('SELECT TRUNCATE(sum(price)*',in_hours,'*',no_of_days,'*',no_of_sitters,',2)');
        SET @theSql=CONCAT(@theSql,' as total_amount from job_prices jp join kids_ages ka on ka.id = jp.kids_age_id');
        SET @theSql=CONCAT(@theSql,' where ka.age in(',age,') and start_hours > ',in_hours,' AND ');
        SET @theSql=CONCAT(@theSql,in_hours,'<= end_hours');
        PREPARE stmt from @theSql; -- create a prepared stmt from the above concat
        EXECUTE stmt;   -- run it
        DEALLOCATE PREPARE stmt;    -- cleanup
    END$
    DELIMITER ;
    

    MySqL 手册页SQL Syntax for Prepared Statements.

    注意,上面的CONCAT() 只会在用户变量(带有@ 符号)的情况下成功。不是带有DECLARE 的局部变量。

    【讨论】:

    • 您的方法很好,但对我不起作用。给出错误或空结果。致电sitter_price2(4, '1,2,3,4', 1, 5); - 如果小时数设置 >4 给出结果,则给出错误结果 CALL sitter_price2(5, '1,2,3,4', 1, 5); - 给空
    • 重要的是它产生的 sql 字符串正是它应该的。然后它执行它。因此,可以在第 1 步中工作以实现这一目标。如果正确,问题就出在您的数据上。
    • 换句话说,EXECUTE 执行您想要的查询。如果产生了错误的数字,那么您的数据不是您所期望的。
    【解决方案2】:

    下面是我自己的问题的答案

    CREATE PROCEDURE `sitter_price`(
       in in_hours float,
       in age varchar(100),
       in no_of_sitters int,
       in no_of_days int
    )
    BEGIN
     select 
      TRUNCATE(sum(price)*in_hours*no_of_days*no_of_sitters,2) as total_amount
      from job_prices jp
      join kids_ages ka on ka.id = jp.kids_age_id
     where 
      jp.status = 1 and 
      find_in_set(ka.age,age) and
      in_hours between jp.start_hours and jp.end_hours;
    END
    

    调用过程

    CALL `usitterz`.`sitter_price`(6, '1,2,3,4', 1, 5);
    

    【讨论】:

    • 你的不会使用索引。我的会。正如我在this other Answer 中解释的那样
    • 如果您编写的代码以find_in_set() 结尾作为解决方案,您可能做错了什么,应该像在堆栈上那样四处询问。并不是每个人都像我一样坐在那里优化事情。他们可能很乐意告诉你想听。
    • Drew 你为什么这么生气。你的 sp 没有给出正确的结果。你的sp可能是对的。但没有给我结果。留下您的电子邮件 ID,我将发送包含数据的表格,然后您就可以确定谁是正确的您或我。
    • 谁说我生气了。我很高兴为人们编写代码。我喜欢它。
    • 留下您的电子邮件 ID 或我给您的桌子在哪里?
    【解决方案3】:

    另一个答案

    CREATE DEFINER=`root`@`localhost` PROCEDURE `sitter_price`(
       in in_hours float,
       in age varchar(100),
       in no_of_sitters int,
       in no_of_days int
    )
    BEGIN
        SET @theSql=CONCAT('SELECT TRUNCATE(sum(price)*',in_hours,'*',no_of_days,'*',no_of_sitters,',2)');
        SET @theSql=CONCAT(@theSql,' as total_amount from job_prices jp join kids_ages ka on ka.id = jp.kids_age_id');
        SET @theSql=CONCAT(@theSql,' where ka.age in(',age,') and ' ,in_hours, ' between jp.start_hours and jp.end_hours ');      
        PREPARE stmt from @theSql; -- create a prepared stmt from the above concat
        EXECUTE stmt;   -- run it
        DEALLOCATE PREPARE stmt;    -- cleanup
    END
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-08-29
      • 2011-01-12
      • 1970-01-01
      • 2015-01-29
      • 2018-08-10
      • 1970-01-01
      相关资源
      最近更新 更多