CodeIgniter(SQLSRV)调用SQL Server存储过程执行不全问题求助
首先可以确定:存储过程本身没有问题——毕竟在SSMS里能完整执行4个流程,说明逻辑是完全成立的。问题大概率出在PHP SQLSRV驱动和CodeIgniter的结果集处理逻辑上。
核心原因
SQL Server默认会给每个执行的SQL语句返回「影响行数」的结果集(比如每个INSERT都会返回(1 row affected))。当你通过CodeIgniter调用存储过程时,SQLSRV驱动会把这些中间结果集当成独立的查询结果,如果不手动处理这些结果集,驱动会在处理完前两个结果集后停止,导致存储过程后续的流程3、4没机会执行。
具体解决方案
方案1:修改存储过程(最推荐)
在存储过程的最开头添加SET NOCOUNT ON;,让SQL Server不再返回每个语句的影响行数,这样驱动就不会被中间结果集打断:
CREATE PROCEDURE getwage_bcmbs @date_start DATE AS BEGIN SET NOCOUNT ON; -- 新增这一行 -- 流程1:从Chief 1查询插入Archive INSERT INTO Archive (...) SELECT ... FROM Chief1 WHERE date = @date_start; -- 流程2:从Chief 2查询插入Archive INSERT INTO Archive (...) SELECT ... FROM Chief2 WHERE date = @date_start; -- 流程3:从Chief 3查询插入Archive INSERT INTO Archive (...) SELECT ... FROM Chief3 WHERE date = @date_start; -- 流程4:从Chief 4查询插入Archive INSERT INTO Archive (...) SELECT ... FROM Chief4 WHERE date = @date_start; END
修改后重新生成存储过程,再通过CodeIgniter调用试试,应该能完整执行4个流程。
方案2:不修改存储过程,在CodeIgniter中处理所有结果集
如果不能修改存储过程,可以在执行完查询后,手动遍历所有结果集,确保存储过程执行完所有步骤:
// 调用存储过程 $query = $this->db->query("EXEC getwage_bcmbs @date_start = '2020-04-28'"); // 遍历所有结果集,推进到存储过程结束 do { // 无需处理结果,只是让驱动跳过中间的影响行数结果集 } while (sqlsrv_next_result($query->result_id));
方案3:更新SQLSRV驱动
你使用的是PHP7.2 + Ubuntu环境,deb.sury.org的包可能自带的SQLSRV驱动不是最新版,旧版本可能存在多结果集处理的bug。可以更新到适配PHP7.2的最新稳定版驱动——Ubuntu下可以通过pecl工具或者手动编译的方式完成更新。
方案4:排查存储过程的隐藏逻辑(兜底验证)
虽然SSMS里执行正常,但可以在存储过程中添加日志验证,比如新增一个日志表,每个流程执行后插入一条日志记录:
-- 先创建临时日志表 CREATE TABLE Proc_Log ( LogID INT IDENTITY(1,1) PRIMARY KEY, StepName VARCHAR(50), ExecuteTime DATETIME DEFAULT GETDATE() ); -- 在存储过程每个流程后添加日志 INSERT INTO Proc_Log (StepName) VALUES ('流程1执行完成'); -- ... 流程2、3、4后分别添加对应日志
然后通过CodeIgniter调用存储过程后,查看Proc_Log表的记录:如果只有前两条,说明驱动确实没让存储过程执行到后面;如果四条都有,那可能是后续的INSERT因为某些环境差异没插入数据(但SSMS里正常的话这个可能性极低)。
内容的提问来源于stack exchange,提问作者Parmin Supaidi ST

