执行此过程时遇到的问题:
call `sp_frm4_px_prc_calc`();
Error Code : 1064
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1
Run Code Online (Sandbox Code Playgroud)
程序是:
SHOW CREATE PROCEDURE sp_frm4_px_prc_calc\G
CREATE DEFINER=`power`@`%` PROCEDURE `sp_frm4_px_prc_calc`()
BEGIN
DECLARE _id INT(5);
DECLARE _SLLR_ID INT(4);
DECLARE _SLLR_STT_ID INT(4);
DECLARE _BYR_ID INT(4);
DECLARE _BYR_STT_ID INT(4);
DECLARE _strt_dt DATE;
DECLARE _end_dt DATE ;
DECLARE _strt_tm TIME;
DECLARE _end_tm TIME;
DECLARE _exchng VARCHAR(20);
DECLARE _stt VARCHAR(250);
DECLARE _st_tm_blck INT(2);
DECLARE _end_tm_blck INT(2);
DECLARE _avg_px_prc DOUBLE(4,2);
DECLARE _done INT(1) DEFAULT 0;
DECLARE _px_rgn_id SMALLINT(2);
DECLARE cur1 CURSOR FOR
SELECT ID,SLLR_ID,SLLR_STT_ID,BYR_ID,BYR_STT_ID,STRT_DT,END_DT,STRT_TM,END_TM
FROM frm4
WHERE TRNS_TYP_ID IN(4,7,10) AND ( avg_px_prc=0.00 OR avg_px_prc IS NULL);
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET _done=1;
OPEN cur1;
REPEAT
FETCH cur1 INTO _id,_SLLR_ID,_SLLR_STT_ID,_BYR_ID,_BYR_STT_ID,_strt_dt,_end_dt,_strt_tm,_end_tm;
-- Finding which column has Exchange Value;
IF (_SLLR_ID IN (SELECT ID FROM entty_frm4 WHERE SHRT_NM IN ('IEX')) AND _BYR_STT_ID IN (SELECT ID FROM entty WHERE ctgry_id IN (1,2))) THEN
SET _exchng=1,_stt=_BYR_STT_ID;
ELSEIF (_SLLR_ID IN (SELECT ID FROM entty_frm4 WHERE SHRT_NM IN ('PXI','PXIL')) AND _BYR_STT_ID IN (SELECT ID FROM entty WHERE ctgry_id IN (1,2))) THEN
SET _exchng=2,_stt=_BYR_STT_ID;
ELSEIF (_BYR_ID IN (SELECT ID FROM entty_frm4 WHERE SHRT_NM IN ('IEX')) AND _SLLR_STT_ID IN (SELECT ID FROM entty WHERE ctgry_id IN (1,2))) THEN
SET _exchng=1,_stt=_SLLR_STT_ID;
ELSEIF (_BYR_ID IN (SELECT ID FROM entty_frm4 WHERE SHRT_NM IN ('PXI','PXIL')) AND _SLLR_STT_ID IN (SELECT ID FROM entty WHERE ctgry_id IN (1,2))) THEN
SET _exchng=2,_stt=_SLLR_STT_ID;
ELSE
SET _exchng=0,_stt=0;
END IF;
IF (_exchng<>0 AND _stt<>0 ) THEN
SELECT MIN(TM_BLCK),MAX(TM_BLCK) INTO _st_tm_blck,_end_tm_blck FROM tm_blck_mstr WHERE STRT_TM>=_strt_tm AND END_TM<=_end_tm;
-- SELECT _id,_exchng,_stt,_strt_dt,_end_dt,_st_tm_blck,_end_tm_blck;
SELECT px_rgn_id INTO _px_rgn_id FROM stt_px_rgn WHERE stt_id=_stt AND exchng_id=_exchng;
-- SELECT CONCAT("Before Change : ",_px_rgn_id," ",_strt_dt," ",_exchng);
IF (_px_rgn_id IN (7,12)) THEN
IF (_px_rgn_id=7 AND _exchng=1 AND _strt_dt<'2011-08-31' ) THEN
SET _px_rgn_id=5;
ELSEIF (_px_rgn_id=12 AND _exchng=1 AND _strt_dt<'2011-09-02' ) THEN
SET _px_rgn_id=10;
ELSEIF (_px_rgn_id=7 AND _exchng=2 AND _strt_dt<'2011-08-31' ) THEN
SET _px_rgn_id=5;
ELSEIF (_px_rgn_id=12 AND _exchng=2) THEN
SET _px_rgn_id=10;
END IF;
END IF;
-- SELECT CONCAT("After Change : ",_px_rgn_id," ",_strt_dt," ",_exchng);
SET @_query=CONCAT("SELECT ROUND(AVG(vl)/1000,2) into @_avg_px_prc FROM px_prc_tb a where a.px_rgn_id=",_px_rgn_id," and a.exchng_id=",_exchng," AND a.dt BETWEEN '",_strt_dt,"' AND '",_end_dt,"' AND a.tm_blck BETWEEN ",_st_tm_blck," AND ",_end_tm_blck,";");
PREPARE stmt FROM @_query;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- select @_query,@_avg_px_prc;
IF (@_avg_px_prc IS NOT NULL) THEN
SET @_queryUpdatePxPrc=CONCAT("update frm4 set avg_px_prc=",@_avg_px_prc," where id=",_id,";");
PREPARE stmtUpdatePxPrc FROM @_queryUpdatePxPrc;
EXECUTE stmtUpdatePxPrc;
DEALLOCATE PREPARE stmtUpdatePxPrc;
-- SELECT @_queryUpdatePxPrc;
ELSE
SET @_queryUpdateErr=CONCAT("INSERT INTO `indiaelectron`.`err` (`PRGRM`,`MSG`) VALUES ('sp_frm4_px_prc_calc','Data not found in px_prc_tb for Row : ",_id,"');");
PREPARE stmtUpdateErr FROM @_queryUpdateErr;
EXECUTE stmtUpdateErr;
DEALLOCATE PREPARE stmtUpdateErr;
-- select @_queryUpdateErr;
END IF ;
ELSE
SET @_queryUpdateErr=CONCAT("INSERT INTO `indiaelectron`.`err` (`PRGRM`,`MSG`) VALUES ('sp_frm4_px_prc_calc','Exchange or State is missing at Row : ",_id,"');");
PREPARE stmtUpdateErr FROM @_queryUpdateErr;
EXECUTE stmtUpdateErr;
DEALLOCATE PREPARE stmtUpdateErr;
-- SELECT @_queryUpdateErr;
END IF;
UNTIL _done=1 END REPEAT;
CLOSE cur1;
END
Run Code Online (Sandbox Code Playgroud)
在您的代码中有几个地方可以使用您使用 CONCAT() 制作的查询字符串来声明准备好的语句。如果CONCAT() 的任何参数为 NULL,则该函数的返回值也是NULL...所以看起来在某些时候您无意中(有效地)这样做了:
mysql> SET @oops = NULL;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT @oops;
+-------+
| @oops |
+-------+
| NULL |
+-------+
1 row in set (0.00 sec)
mysql> PREPARE foo FROM @oops;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that
corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1
Run Code Online (Sandbox Code Playgroud)
同样的错误。
因此,错误最初发生是因为在您用来制作要传递给 PREPARE 语句之一的字符串的变量之一中有一个空值,可能是意外的...强制从 CONCAT() 返回的整个值为空。
但是,在您使用测试和 IFNULL() 追逐那些空值之前,我想补充一点,除非我指出您有另一个问题,或者您可以同时解决两个问题(效率和安全性),否则我的答案是不完整的。
您可以并且可能应该在打开游标之前为所有不同的语句调用 PREPARE,使用 ? 需要从变量传入的值的占位符。之后:
EXECUTE stmt USING @var1, @var2, @var3; # using the appropriate variables.
Run Code Online (Sandbox Code Playgroud)
否则,您会不断地不必要地分配和释放资源,从而降低流程效率(并追查此类错误)。您可以在 proc 结束时解除分配。
除非别无选择,否则应避免使用字符串连接来制作准备好的语句……或任何查询……在任何环境中……。如果这种做法还不是那么普遍,SQL 注入攻击几乎是不可能的。这不安全。当然,它仍然有效,这正是它如此危险的原因。
预准备语句中的占位符不应被视为简单的捷径或便利——它们还维护和强制执行查询和参数之间的边界(更不用说允许服务器仅解析预准备语句一次,使每次执行都比每次需要时将整个事物拆除并重建更快)。您不能将任何内容作为参数传递给准备好的语句,服务器会将其误解为您的查询的一部分。您可以通过串联轻松地无意中做到这一点。
http://dev.mysql.com/doc/refman/5.5/en/sql-syntax-prepared-statements.html
ETA:使用 USING 传递的参数必须是像 @var1 这样的“用户”变量,而不是像 var1 这样的“本地”变量,在 proc 中声明,因为准备好的语句的范围仅限于会话,并且由于基于语句的复制,无论您是是否重新使用它。一个有趣的副作用是,如果您需要在另一个 proc 调用的 proc 中调用相同的准备好的语句(或在您递归调用的 proc 中),您不必在内部 proc 中再次准备它——它是仍然合法......并且您实际上会因为重新声明它而受到很小的性能影响。事实上,在存储过程执行完成后,您没有 DEALLOCATE 的准备好的语句实际上仍然是合法的。
| 归档时间: |
|
| 查看次数: |
2756 次 |
| 最近记录: |