MYSQL动态查询中的字符串问题

时间:2020-10-27 14:50:43

标签: mysql stored-procedures dynamicquery

因此,简而言之,这应该很简单...我有一个静态查询,我试图动态地重新创建它,但是它始终会产生语法错误。令人困惑的是,如果我复制粘贴select @statement输出,它将在MYSQL Workbench中正常运行。

下面,我将过程分为2个独立的execute语句,其中第二个看起来似乎是引起错误的原因,但是我认为这可能会引起误解(我将在下面解释原因)。

CREATE DEFINER=`admin`@`%` PROCEDURE `sp_calc_place_win_per`(

IN var_event_type_id int,
IN var_country varchar(45),
IN var_max_bsp float,
IN var_market_type varchar(45),
IN var_increment float,
IN var_first_increment float

)
BEGIN

drop temporary table if exists tbl_results;

if var_market_type = 'win' then
    set @market_type = var_market_type;
    set @rank = 1;
    set @number_of_winners = 1;
else
    set @market_type = var_market_type;
    set @rank = 2;
    set @number_of_winners = 2;
end if;

-- set @a = 'create temporary table tbl_results';
set @b = concat('create temporary table tbl_results select count(case when bsp between 0 and ', var_first_increment, ' then bsp end) as `0-', convert(var_first_increment,char),'` ');
set @statement = @b; -- concat(@a, @b);
set @start_range = round(var_first_increment + 0.01,2);
REPEAT
    set @end_range = round(round(@start_range + var_increment - 0.01,2),2);
    if @end_range > var_max_bsp - var_increment then
        set @end_range = var_max_bsp;   
    end if;
    set @c = concat(', count(case when bsp between ', round(@start_range,2),' and ', round(@end_range,2), ' then bsp end) as `',convert(@start_range,char),'-', convert(round(@end_range,2),char), '` ');
    set @statement = concat(@statement,@c);
    set @start_range = round(@end_range + 0.01,2);

UNTIL @end_range = var_max_bsp
END REPEAT;
set @d = concat(', count(case when bsp > ', round(@end_range,2), ' then bsp end) as `>', convert(round(@end_range,2),char), '` ');
set @e = concat(', winner FROM tbl_betfair_historic_data where event_id in (select event_id from tbl_betfair_historic_data where rank <=', @rank, ' and market_type ="', @market_type , '" and number_of_winners = ' , @number_of_winners, ' and bsp <=' , var_max_bsp , ' and country_code = "', var_country, '" and event_type_id = ', var_event_type_id, ' group by event_id) group by event_id, winner; ');
set @statement = concat(@statement, @d, @e);
prepare st1 from @statement;
execute st1;

-- This is purely in to test the first section produces the results as expected
select * from tbl_results;

-- This section dynamically creates n variables, depending on the var_max_bsp and var_increment variables
set @bsp = 0;
set @total_count = 0;
set @statement = concat(' set @total_', @total_count, ' = (select sum(b.`', @bsp, '-' , var_first_increment,'`) from tbl_results b);');
set @start_range = var_first_increment + 0.01;
REPEAT
set @total_count = @total_count + 1;
set @end_range = @start_range + var_increment - 0.01;   

if @end_range > var_max_bsp - var_increment then
    set @end_range = var_max_bsp;   
end if;

set @s= concat(' set @total_', convert(@total_count,char), ' = (select sum(b.`', convert(round(@start_range,2),char), '-' , convert(round(@end_range,2),char),'`) from tbl_results b);');
set @statement = concat(@statement, @s);
set @start_range = @end_range + 0.01;
UNTIL @end_range = var_max_bsp
END REPEAT;
set @final_total = concat(' set @total_', convert(@total_count+1,char), ' = (select sum(b.`>', convert(round(@end_range,2),char),'`) from tbl_results b); ');
set @statement = concat(@statement, @final_total);
select @statement;
prepare st1 from @statement;
execute st1;

-- This is what the dynamic query should create
/*
set @total_0 = (select 
sum(a.`0-1.4`)
from tbl_results a);

set @total_141 = (select
sum(a.`1.41-1.6`)
from tbl_results a);

set @total_161 = (select
sum(a.`1.61-1.83`)
from tbl_results a);

set @total_183 = (select 
sum(a.`>1.83`)
from tbl_results a);

--This would then be the final section, below is the hard-coded version

select
sum(a.`0-1.4`)/@total_0 as '0-1.4', 
sum(a.`1.41-1.6`)/@total_141  as '1.41-1.6', 
sum(a.`1.61-1.83`)/@total_161 as '1.61-1.83', 
sum(a.`>1.83`)/@total_183 as '>1.83',
if (winner=1,'winner','loser') as 'winner'
from tbl_results a
group by winner;

*/
drop temporary table if exists tbl_results;

END

如果我运行该代码,它将创建临时表tbl_results,因此第一部分确实可以正常工作,但随后我得到:

14:36:31    call sp_calc_place_win_per(4339, 'GB', 1.83, 'place', 0.2, 1.4) Error Code: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'set @total_1 = (select sum(b.`1.41-1.60`) from tbl_results b); set @total_2 = (s' at line 1   

但是,如果我将过去的代码复制到Workbench中,则可以正常工作。

如果我连接两个@语句并作为一个语句运行,则这是它生成的SQL(产生相同的错误):

'create temporary table tbl_results select count(case when bsp between 0 and 1.4 then bsp end) as `0-1.4` , count(case when bsp between 1.41 and 1.60 then bsp end) as `1.41-1.60` , count(case when bsp between 1.61 and 1.83 then bsp end) as `1.61-1.83` , count(case when bsp > 1.83 then bsp end) as `>1.83` , winner FROM tbl_betfair_historic_data where event_id in (select event_id from tbl_betfair_historic_data where rank <=2 and market_type =\"place\" and number_of_winners = 2 and bsp <=1.83 and country_code = \"GB\" and event_type_id = 4339 group by event_id) group by event_id, winner;  set @total_0 = (select sum(b.`0-1.4`) from tbl_results b); set @total_1 = (select sum(b.`1.41-1.60`) from tbl_results b); set @total_2 = (select sum(b.`1.61-1.83`) from tbl_results b); set @total_3 = (select sum(b.`>1.83`) from tbl_results b); '

所以我确实想知道字符串是否可能引起了问题(例如country_code =和market_type =),因为“ GB”显然无法在MYSQL工作台中使用,但是如果我重新格式化这些字符串,整个事情就可以了(仅在Workbench中)。

我尝试过各种方法来重新格式化字符串,但是没有运气,但是我也不能100%确信这是问题所在,因为我可以验证我是否保留代码的原样(即使用2 x @statement)正在执行),然后从tbl_results中的select *中可以验证它确实创建了该表)。

希望这是足够的信息,但是如果某些部分没有意义,请告诉我,我将尝试扩展。

我完全被困在这里,因此不胜感激(感谢您,没有换行符,这是很抱歉的,这是因为有关该主题的先前类似问题建议换行符可能导致动态MYSQL存储过程出现问题)!

[UPDATE],我们现在可以确定问题出在我代码的“第2部分”,我为第一部分创建了一个单独的过程,但是还包括了一个虚拟临时表的创建,因此它可能人们更容易复制我看到的错误:

CREATE DEFINER=`admin`@`%` PROCEDURE `sp_calc_place_win_per`(

IN var_event_type_id int,
IN var_country varchar(45),
IN var_max_bsp float,
IN var_market_type varchar(45),
IN var_increment float,
IN var_first_increment float

)
BEGIN

drop temporary table if exists tbl_results;

set @event_type_id = var_event_type_id;
set @country = var_country;
set @max_bsp = var_max_bsp;
set @market_type = var_market_type;
set @increment = var_increment;
set @first_increment = var_first_increment;

/*
prepare create_results_table from 'CALL sp_create_results_table(?,?,?,?,?,?)';
execute create_results_table using 
@event_type_id, @country, @max_bsp, 
@market_type, @increment, @first_increment;*/

-- Create Dummy tbl_results for testing

create temporary table tbl_results
(`0-1.40` float NOT NULL,
`1.41-1.60` float NOT NULL,
`1.61-1.83` float NOT NULL,
`>1.83` float NOT NULL
);

INSERT INTO tbl_results
(`0-1.40`,
`1.41-1.60`,
`1.61-1.83`,
`>1.83`)
VALUES (7, 5, 3, 2);

set @bsp = 0;
set @total_count = 0;
set @statement = concat(' select sum(tbl_results.`', @bsp, '-' , var_first_increment,'`) into @total_', @total_count,
 ' from tbl_results;');
set @start_range = var_first_increment + 0.01;
REPEAT
set @total_count = @total_count + 1;
set @end_range = @start_range + var_increment - 0.01;   

if @end_range > var_max_bsp - var_increment then
    set @end_range = var_max_bsp;   
end if;

set @s= concat(' select sum(tbl_results.`', convert(round(@start_range,2),char), '-' , 
convert(round(@end_range,2),char),'`) into @total_', convert(@total_count,char), ' from tbl_results;');
set @statement = concat(@statement, @s);
set @start_range = @end_range + 0.01;
UNTIL @end_range = var_max_bsp
END REPEAT;

set @final_total = concat(' select sum(tbl_results.`>', convert(round(@end_range,2),char),'`) into @total_', 
convert(@total_count+1,char), ' from tbl_results; ');
set @statement = concat(@statement, ' ', @final_total);
SELECT @statement;
prepare st1 from @statement;
execute st1;

/*

set @total_0 = (select 
sum(a.`0-1.4`)
from tbl_results a);

set @total_141 = (select
sum(a.`1.41-1.6`)
from tbl_results a);

set @total_161 = (select
sum(a.`1.61-1.83`)
from tbl_results a);

set @total_183 = (select 
sum(a.`>1.83`)
from tbl_results a);

select
sum(a.`0-1.4`)/@total_0 as '0-1.4', 
sum(a.`1.41-1.6`)/@total_141  as '1.41-1.6', 
sum(a.`1.61-1.83`)/@total_161 as '1.61-1.83', 
sum(a.`>1.83`)/@total_183 as '>1.83',
if (winner=1,'winner','loser') as 'winner'
from tbl_results a
group by winner;

select @statement;
*/
drop temporary table if exists tbl_results;

0 个答案:

没有答案