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

MySQL存储过程执行报错#2014:命令不同步问题求助

问题描述

我写了两个存储过程,用来统计每个订单的总购票数(订单数据可能分散在多行)。已经确认BEGIN、END和DELIMITER的使用没问题,但执行SQL时出现两个错误:

  1. 静态分析提示:Missing expression. (near "ON" at position 25)
  2. MySQL返回错误:#2014 - Commands out of sync; you can't run this command now

排查后发现,只有执行最后一行CALL getTotalTicketsBoughtPerOrder(@idCount);时会触发报错,进一步定位到问题出在存储过程getTotalTicketsBoughtPerOrder的WHILE循环内的SELECT @totalTicketsBought ;语句,但不清楚具体原因。

相关代码

存储过程及执行SQL

DROP PROCEDURE IF EXISTS getTotalTicketsPerOrder;
DROP PROCEDURE IF EXISTS getTotalTicketsBoughtPerOrder;
DELIMITER //
CREATE PROCEDURE getTotalTicketsPerOrder(
    IN pOrderID INT(11),
    OUT pTotalTickets INT(11)
)
BEGIN
    SELECT SUM(ticketsinorder.NoOfTicketsBought)
    INTO pTotalTickets
FROM
    ticketsinorder
WHERE
    ticketsinorder.OrderID = pOrderID ;
END //
DELIMITER ;
DELIMITER //
CREATE PROCEDURE getTotalTicketsBoughtPerOrder(IN idCount INT(11))
BEGIN
    DECLARE counter INT DEFAULT 1;
    WHILE counter <= idCount DO
CALL getTotalTicketsPerOrder(counter, @totalTicketsBought) ;
SELECT @totalTicketsBought ;
SET counter = counter + 1 ;
END WHILE ;
END //
DELIMITER ;
SELECT @idCount := COUNT(orders.OrderID)
FROM orders;
CALL getTotalTicketsBoughtPerOrder(@idCount);

错误日志

2022-08-22 20:10:26 0 [Note] mysqld.exe: Aria engine: recovery done
2022-08-22 20:10:26 0 [Note] InnoDB: Mutexes and rw_locks use Windows interlocked functions
2022-08-22 20:10:26 0 [Note] InnoDB: Uses event mutexes
2022-08-22 20:10:26 0 [Note] InnoDB: Compressed tables use zlib 1.2.11
2022-08-22 20:10:26 0 [Note] InnoDB: Number of pools: 1
2022-08-22 20:10:26 0 [Note] InnoDB: Using SSE2 crc32 instructions
2022-08-22 20:10:26 0 [Note] InnoDB: Initializing buffer pool, total size = 16M, instances = 1, chunk size = 16M
2022-08-22 20:10:26 0 [Note] InnoDB: Completed initialization of buffer pool
2022-08-22 20:10:26 0 [Note] InnoDB: Starting crash recovery from checkpoint LSN=2084794
2022-08-22 20:10:26 0 [Note] InnoDB: 128 out of 128 rollback segments are active.
2022-08-22 20:10:26 0 [Note] InnoDB: Removed temporary tablespace data file: "ibtmp1"
2022-08-22 20:10:26 0 [Note] InnoDB: Creating shared tablespace for temporary tables
2022-08-22 20:10:26 0 [Note] InnoDB: Setting file 'C:\xampp\mysql\data\ibtmp1' size to 12 MB. Physically writing the file full; Please wait ...
2022-08-22 20:10:26 0 [Note] InnoDB: File 'C:\xampp\mysql\data\ibtmp1' size is now 12 MB.
2022-08-22 20:10:26 0 [Note] InnoDB: Waiting for purge to start
2022-08-22 20:10:26 0 [Note] InnoDB: 10.4.22 started; log sequence number 2084803; transaction id 4233
2022-08-22 20:10:26 0 [Note] InnoDB: Loading buffer pool(s) from C:\xampp\mysql\data\ib_buffer_pool
2022-08-22 20:10:26 0 [Note] Plugin 'FEEDBACK' is disabled.
2022-08-22 20:10:26 0 [Note] InnoDB: Buffer pool(s) load completed at 220822 20:10:26
2022-08-22 20:10:26 0 [Note] Server socket created on IP: '::'.
解决方案

错误原因

#2014 - Commands out of sync错误的核心原因是:存储过程getTotalTicketsBoughtPerOrder的WHILE循环中,每次执行SELECT @totalTicketsBought ;都会向客户端返回一个独立结果集。循环多次执行时会连续返回多个结果集,而多数SQL客户端(比如phpMyAdmin)无法正确处理这种连续多结果集的情况,从而触发同步错误。

修复方案

方案1:用单条SQL直接统计(推荐)

完全不需要存储过程,通过分组查询就能高效实现需求,还能避免循环带来的性能问题:

SELECT 
    orders.OrderID,
    COALESCE(SUM(ticketsinorder.NoOfTicketsBought), 0) AS TotalTicketsBought
FROM orders
LEFT JOIN ticketsinorder ON orders.OrderID = ticketsinorder.OrderID
GROUP BY orders.OrderID;

用COALESCE可以确保没有购票记录的订单也返回0,而不是NULL。

方案2:修改存储过程,避免多结果集

如果一定要用存储过程,可以把循环结果收集到临时表中,最后一次性返回:

DROP PROCEDURE IF EXISTS getTotalTicketsPerOrder;
DROP PROCEDURE IF EXISTS getTotalTicketsBoughtPerOrder;
DELIMITER //
CREATE PROCEDURE getTotalTicketsPerOrder(
    IN pOrderID INT(11),
    OUT pTotalTickets INT(11)
)
BEGIN
    SELECT COALESCE(SUM(ticketsinorder.NoOfTicketsBought), 0)
    INTO pTotalTickets
    FROM ticketsinorder
    WHERE ticketsinorder.OrderID = pOrderID ;
END //
DELIMITER ;
DELIMITER //
CREATE PROCEDURE getTotalTicketsBoughtPerOrder(IN idCount INT(11))
BEGIN
    DECLARE counter INT DEFAULT 1;
    -- 创建临时表存储结果
    CREATE TEMPORARY TABLE IF NOT EXISTS OrderTicketTotals (
        OrderID INT(11),
        TotalTickets INT(11)
    );
    TRUNCATE TABLE OrderTicketTotals;
    
    WHILE counter <= idCount DO
        CALL getTotalTicketsPerOrder(counter, @totalTicketsBought) ;
        -- 将结果插入临时表
        INSERT INTO OrderTicketTotals (OrderID, TotalTickets) VALUES (counter, @totalTicketsBought);
        SET counter = counter + 1 ;
    END WHILE ;
    
    -- 一次性返回所有结果
    SELECT * FROM OrderTicketTotals;
    DROP TEMPORARY TABLE IF EXISTS OrderTicketTotals;
END //
DELIMITER ;
SELECT @idCount := COUNT(orders.OrderID) FROM orders;
CALL getTotalTicketsBoughtPerOrder(@idCount);

关于静态分析错误

静态分析提示的Missing expression. (near "ON" at position 25)大概率是SQL编辑器的误报,你的代码本身没有语法错误,修复上述多结果集问题后,这个提示应该会自动消失。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 10:39:16