无需循环实现SQL Server多笔更新 避免多次调用ExecSQL的方法
避免多次调用ExecSQL的实现方案
原有循环执行的方案不仅会产生多次数据库交互开销,直接拼接SQL还存在SQL注入风险、单引号语法错误问题,可通过以下方案优化为单次执行:
- 方案1:拼接单条多条件UPDATE语句
通过CASE WHEN语法将所有行的更新规则合并到同一条SQL中,仅需执行一次即可完成全部更新,适配所有支持标准SQL的数据库。
实现示例:
var sqlBuilder: TStringBuilder; // 也可用TStringList替代 a: Integer; idList: TStringList; begin sqlBuilder := TStringBuilder.Create; idList := TStringList.Create; try sqlBuilder.Append('UPDATE dbtable SET atext = CASE id '); for a := 1 to 100 do begin // 转义文本中的单引号避免SQL语法错误 var text := StringReplace(stringgrid.Cells[5,a], '''', '''''', [rfReplaceAll]); var fid := stringgrid.Cells[0,a]; sqlBuilder.AppendFormat('WHEN %s THEN ''%s'' ', [fid, text]); idList.Add(fid); end; sqlBuilder.Append('END WHERE id IN (' + idList.DelimitedText + ')'); query.SQL.Text := sqlBuilder.ToString; query.ExecSQL; finally idList.Free; sqlBuilder.Free; end; end;
- 方案2:使用参数数组批量执行
如果你使用的是FireDAC、ADO等支持参数数组绑定的数据库连接库,可以直接给预处理SQL绑定多组参数,一次提交全部执行,无需拼接SQL,天然避免注入问题。
以FireDAC为例的实现示例:
var a: Integer; begin // 预处理SQL模板 query.SQL.Text := 'UPDATE dbtable SET atext = :atext WHERE id = :id'; // 设置参数数组长度为需要更新的行数 query.Params.ArraySize := 100; for a := 1 to 100 do begin // 数组下标从0开始 query.ParamByName('atext').AsString[a-1] := stringgrid.Cells[5,a]; query.ParamByName('id').AsInteger[a-1] := StrToInt(stringgrid.Cells[0,a]); end; // 一次执行所有更新 query.Execute(100, 0); end;
- 方案3:临时表关联更新(适合更新行数>1000的场景)
如果需要更新的行数非常多,可先批量将所有id和对应atext值插入临时表,再通过表关联语句一次完成全部更新,性能优于前两种方案。
内容的提问来源于stack exchange,提问作者Giannis
相关产品推荐
相关产品推荐

