You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

创建MySQL存储过程时出现Error 1064错误的排查与解决

存储过程创建报错排查与MySQL/Oracle语法差异

问题描述

从Oracle切换到MySQL后,创建名为HITUNGMASUK的存储过程时出现两处Error 1064语法错误:

  1. 参数定义行附近语法错误
  2. 执行DELIMITER;命令时出错

报错信息

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 'ZID_TRANSAKSI VARCHAR(64),
   ZTGL1 DATE,
   ZTGL2 DATE 
) 
BEGIN 
  DECLARE ...' at line 2

--------------------------------------------------

Query: DELIMITER;

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 'DELIMITER' at line 1

原存储过程代码

DELIMITER $$ CREATE PROCEDURE HITUNGMASUK 
(
   ZID_TRANSAKSI VARCHAR(64),
   ZTGL1 DATE,
   ZTGL2 DATE 
) 

BEGIN 
  DECLARE done INT DEFAULT FALSE;
   DECLARE PTAHUN VARCHAR(4);
   DECLARE PBULAN VARCHAR(2);
   DECLARE PHITUNG INTEGER DEFAULT 0; 
   DECLARE CEKKARTUSTOK INTEGER DEFAULT 0;
   DECLARE PID_BARANG VARCHAR(255) DEFAULT 'X';
   DECLARE PPANJANG INTEGER DEFAULT 0;
   DECLARE CEKKARTUSTOK CURSOR FOR
   SELECT B.id_barang, SUM(B.total_Panjang) AS PANJANG
      FROM transaksi_gudang A,
           line_item_barang B
      WHERE A.ID_Transaksi LIKE ZID_TRANSAKSI 
      AND   A.Tanggal BETWEEN ZTGL1 AND ZTGL2
      AND   B.ID_GR = A.ID_Transaksi
      GROUP BY B.id_barang;
    
   DECLARE
     CONTINUE HANDLER FOR NOT FOUND
   SET
    done = TRUE;


   PTAHUN = YEAR(ZTGL1);
   PBULAN = MONTH(ZTGL1);
  
   OPEN CEKKARTUSTOK;
   teams_loop:
   LOOP
      FETCH CEKKARTUSTOK INTO PID_BARANG,PPANJANG;
   
       IF PID_BARANG = 'X' THEN
          INSERT INTO kartustok(TAHUN,BULAN,ID_BARANG,KODE_GUDANG,MASUK) VALUES ();
       END IF;    
   
      IF done THEN LEAVE teams_loop;
      END IF;

   END LOOP;
  CLOSE CEKKARTUSTOK;


   
   SELECT 
   FROM kartustok C 
   WHERE C.TAHUN = PTAHUN
   AND   C.BULAN = PBULAN
   AND   C.ID_BARANG = P
   
   
END $$ DELIMITER;

错误原因与修复方案

1. DELIMITER命令语法错误

  • 原因:DELIMITER命令后必须跟空格和目标分隔符,原代码中DELIMITER;没有空格,MySQL无法识别;同时DELIMITER $$与CREATE PROCEDURE连写易导致解析混淆。
  • 修复:恢复分隔符时使用DELIMITER ;(注意DELIMITER和;之间的空格),且DELIMITER $$后换行再写CREATE PROCEDURE。

2. 参数与变量定义错误

  • 原因1:MySQL存储过程参数需显式指定IN/OUT/INOUT模式(默认虽为IN,但省略会触发解析异常);另外变量CEKKARTUSTOK既被声明为整数又被声明为游标,命名冲突。
  • 修复1:参数前添加IN标识,重命名整数变量为CEKKARTUSTOK_COUNT避免与游标冲突。
  • 原因2:MySQL变量赋值必须使用SET关键字,原代码中PTAHUN = YEAR(ZTGL1);是Oracle写法,MySQL不支持。
  • 修复2:改为SET PTAHUN = YEAR(ZTGL1);、SET PBULAN = MONTH(ZTGL1);。

3. 其他逻辑语法错误

  • INSERT INTO的VALUES()为空,需补充对应列的有效值;
  • SELECT语句未指定查询列,需明确列名;
  • WHERE子句中C.ID_BARANG = P的P未定义,修正为已声明的PID_BARANG;
  • 游标处理顺序错误:应先判断done状态再执行业务逻辑,避免处理空数据。

修复后的完整代码

DELIMITER $$
CREATE PROCEDURE HITUNGMASUK 
(
   IN ZID_TRANSAKSI VARCHAR(64),
   IN ZTGL1 DATE,
   IN ZTGL2 DATE 
) 
BEGIN 
  DECLARE done INT DEFAULT FALSE;
  DECLARE PTAHUN VARCHAR(4);
  DECLARE PBULAN VARCHAR(2);
  DECLARE PHITUNG INTEGER DEFAULT 0; 
  DECLARE CEKKARTUSTOK_COUNT INTEGER DEFAULT 0; -- 重命名避免与游标冲突
  DECLARE PID_BARANG VARCHAR(255) DEFAULT 'X';
  DECLARE PPANJANG INTEGER DEFAULT 0;
  
  -- 游标声明需放在所有变量声明之后
  DECLARE CEKKARTUSTOK CURSOR FOR
    SELECT B.id_barang, SUM(B.total_Panjang) AS PANJANG
    FROM transaksi_gudang A
    JOIN line_item_barang B ON B.ID_GR = A.ID_Transaksi -- 使用标准JOIN语法替代旧写法
    WHERE A.ID_Transaksi LIKE ZID_TRANSAKSI 
      AND A.Tanggal BETWEEN ZTGL1 AND ZTGL2
    GROUP BY B.id_barang;
    
  DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;

  -- MySQL变量赋值必须用SET
  SET PTAHUN = YEAR(ZTGL1);
  SET PBULAN = MONTH(ZTGL1);
  
  OPEN CEKKARTUSTOK;
  teams_loop: LOOP
    FETCH CEKKARTUSTOK INTO PID_BARANG, PPANJANG;
    
    -- 先判断是否遍历完成,避免处理空数据
    IF done THEN
      LEAVE teams_loop;
    END IF;
    
    -- 修正INSERT逻辑,补充有效值示例
    IF PID_BARANG = 'X' THEN
      INSERT INTO kartustok(TAHUN,BULAN,ID_BARANG,KODE_GUDANG,MASUK) 
      VALUES (PTAHUN, PBULAN, PID_BARANG, 'DEFAULT_GUDANG', PPANJANG);
    END IF;    

  END LOOP teams_loop;
  CLOSE CEKKARTUSTOK;

  -- 修正SELECT语句,指定查询列与变量名
  SELECT *
  FROM kartustok C 
  WHERE C.TAHUN = PTAHUN
    AND C.BULAN = PBULAN
    AND C.ID_BARANG = PID_BARANG;
END $$
DELIMITER ; -- 注意DELIMITER与;之间的空格

MySQL与Oracle存储过程核心语法差异

  • 参数模式:MySQL必须显式指定IN/OUT/INOUT(默认IN但建议显式声明),Oracle可省略默认IN;
  • 变量赋值:MySQL用SET 变量 = 值,Oracle支持直接变量 = 值;
  • 分隔符处理:MySQL需要用DELIMITER临时修改语句分隔符,避免存储过程内的;提前结束解析,Oracle无需此操作;
  • 命名规则:MySQL不允许变量与游标同名,Oracle无此限制;
  • 日期函数:MySQL直接用YEAR(date)/MONTH(date),Oracle需用EXTRACT(YEAR FROM date)或TO_CHAR(date, 'YYYY');
  • 游标循环:MySQL支持LOOP...END LOOP加标签,Oracle除LOOP外还支持FOR...IN游标循环;
  • 处理程序位置:MySQL的DECLARE HANDLER必须放在所有变量/游标声明之后,Oracle的异常处理位置更灵活。

内容的提问来源于stack exchange,提问作者Kevin Elia

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 19:47:59