Sql server Delphi-MS SQL 2014中的多个循环插入
我需要循环抛出tstringlist并为每个项目执行insert。现在我的代码是:Sql server Delphi-MS SQL 2014中的多个循环插入,sql-server,delphi,insert,Sql Server,Delphi,Insert,我需要循环抛出tstringlist并为每个项目执行insert。现在我的代码是: for i := 0 to TS2.Count - 1 do begin aqZapisz.SQL.Text := 'INSERT INTO projekty_koszty_rozb ' + '(id_kosztu,id_projektu, nr_dokumentu, pozycja,id_grupy, id_rodzaju, id_typu, data_dok
for i := 0 to TS2.Count - 1 do
begin
aqZapisz.SQL.Text := 'INSERT INTO projekty_koszty_rozb ' +
'(id_kosztu,id_projektu, nr_dokumentu, pozycja,id_grupy, id_rodzaju, id_typu, data_dok, '
+ 'data_pla, data_ksi,mc,rok,kwota) ' +
'VALUES(:p1,:p2, :p3, :p4, :p5, :p6, :p7, :p8, :p9,:p10,:p11,:p12,:p13)';
aqZapisz.Parameters.ParamByName('p1').Value := idk;
aqZapisz.Parameters.ParamByName('p2').Value := TS2[i];
aqZapisz.Parameters.ParamByName('p3').Value := edtNrDok.Text;
aqZapisz.Parameters.ParamByName('p4').Value := edtPoz.Text;
aqZapisz.Parameters.ParamByName('p5').Value := id_grupy;;
aqZapisz.Parameters.ParamByName('p6').Value := id_rodzaju;
aqZapisz.Parameters.ParamByName('p7').Value := id_typu;
aqZapisz.Parameters.ParamByName('p8').Value :=
DateToStr(zxDateDok.Date);
aqZapisz.Parameters.ParamByName('p9').Value :=
DateToStr(zxDatePlat.Date);
aqZapisz.Parameters.ParamByName('p10').Value :=
DateToStr(zxDateKsieg.Date);
aqZapisz.Parameters.ParamByName('p11').Value :=
IntToStr(Integer(MonthOf(zxDateKsieg.Date)));
aqZapisz.Parameters.ParamByName('p12').Value :=
IntToStr(Integer(YearOf(zxDateKsieg.Date)));
aqZapisz.Parameters.ParamByName('p13').Value :=
RoundTo((StrToFloat(edtWartosc.Text) /
listazaznprojektow.Count), -2);
aqZapisz.ExecSQL;
aqZapisz.SQL.Clear;
end;
但插入时间约为2分钟,TS2中有1700个项目。如何提高速度???不要每次循环都替换SQL语句。在循环开始之前设置一次,然后只更新循环内的参数
aqZapisz.SQL.Text := 'INSERT INTO projekty_koszty_rozb ' +
'(id_kosztu,id_projektu, nr_dokumentu, pozycja,id_grupy, id_rodzaju, id_typu, data_dok, '
+ 'data_pla, data_ksi,mc,rok,kwota) ' +
'VALUES(:p1,:p2, :p3, :p4, :p5, :p6, :p7, :p8, :p9,:p10,:p11,:p12,:p13)';
for i := 0 to TS2.Count - 1 do
begin
aqZapisz.Parameters.ParamByName('p1').Value := idk;
aqZapisz.Parameters.ParamByName('p2').Value := TS2[i];
aqZapisz.Parameters.ParamByName('p3').Value := edtNrDok.Text;
aqZapisz.Parameters.ParamByName('p4').Value := edtPoz.Text;
aqZapisz.Parameters.ParamByName('p5').Value := id_grupy;;
aqZapisz.Parameters.ParamByName('p6').Value := id_rodzaju;
aqZapisz.Parameters.ParamByName('p7').Value := id_typu;
aqZapisz.Parameters.ParamByName('p8').Value :=
DateToStr(zxDateDok.Date);
aqZapisz.Parameters.ParamByName('p9').Value :=
DateToStr(zxDatePlat.Date);
aqZapisz.Parameters.ParamByName('p10').Value :=
DateToStr(zxDateKsieg.Date);
aqZapisz.Parameters.ParamByName('p11').Value :=
IntToStr(Integer(MonthOf(zxDateKsieg.Date)));
aqZapisz.Parameters.ParamByName('p12').Value :=
IntToStr(Integer(YearOf(zxDateKsieg.Date)));
aqZapisz.Parameters.ParamByName('p13').Value :=
RoundTo((StrToFloat(edtWartosc.Text) /
listazaznprojektow.Count), -2);
aqZapisz.ExecSQL;
end;
最大的影响是您正在一个接一个地执行多个SQL语句。这包括调用服务器、等待响应以及随之而来的所有额外流量。您有两个选择: 1) 您可以尝试一个接一个地添加所有sql语句,然后在末尾执行一条execsql语句。您需要“作弊”并内联p2参数。如果您选择此路由,您应该自己清理该参数,以防止SQL注入之类的事情。您也可以在X记录中批量执行此操作
baseSQL1 := 'INSERT INTO projekty_koszty_rozb ' +
'(id_kosztu,id_projektu, nr_dokumentu, pozycja,id_grupy, id_rodzaju, id_typu, data_dok, '
+ 'data_pla, data_ksi,mc,rok,kwota) ' +
'VALUES(:p1, '+
baseSQL2 := ', :p3, :p4, :p5, :p6, :p7, :p8, :p9,:p10,:p11,:p12,:p13);';
aqZapisz.SQL.Clear;
for i := 0 to TS2.Count - 1 do
begin
aqZapisz.SQL.Add(baseSQL1 + TS2[i] + baseSQL2);
end;
aqZapisz.Parameters.ParamByName('p1').Value := idk;
aqZapisz.Parameters.ParamByName('p3').Value := edtNrDok.Text;
aqZapisz.Parameters.ParamByName('p4').Value := edtPoz.Text;
aqZapisz.Parameters.ParamByName('p5').Value := id_grupy;;
aqZapisz.Parameters.ParamByName('p6').Value := id_rodzaju;
aqZapisz.Parameters.ParamByName('p7').Value := id_typu;
aqZapisz.Parameters.ParamByName('p8').Value :=
DateToStr(zxDateDok.Date);
aqZapisz.Parameters.ParamByName('p9').Value :=
DateToStr(zxDatePlat.Date);
aqZapisz.Parameters.ParamByName('p10').Value :=
DateToStr(zxDateKsieg.Date);
aqZapisz.Parameters.ParamByName('p11').Value :=
IntToStr(Integer(MonthOf(zxDateKsieg.Date)));
aqZapisz.Parameters.ParamByName('p12').Value :=
IntToStr(Integer(YearOf(zxDateKsieg.Date)));
aqZapisz.Parameters.ParamByName('p13').Value :=
RoundTo((StrToFloat(edtWartosc.Text) /
listazaznprojektow.Count), -2);
aqZapisz.ExecSQL;
2) 您可以创建一个存储过程并一次性发送所有数据。完全没有经过测试
CREATE PROCEDURE (@p1 nvarchar(max), @p2 nvarchar(max), @p3 nvarchar(max), @p4 nvarchar(max), @p5 nvarchar(max), @p6 nvarchar(max), @p7 nvarchar(max), @p8 nvarchar(max), @p9 nvarchar(max), @p10 nvarchar(max), @p11 nvarchar(max), @p12 nvarchar(max), @p13 nvarchar(max))
AS
BEGIN
DECLARE @idx1 INT;
DECLARE @idx2 INT;
SET @idx1=0;
WHILE @idx1 >-1
BEGIN;
SELECT @idx2 = CHARINDEX(CHAR(13),@p2,@idx1);
IF @idx2 > 0
BEGIN;
INSERT INTO projekty_koszty_rozb
(id_kosztu, id_projektu, nr_dokumentu, pozycja, id_grupy, id_rodzaju, id_typu, data_dok, data_pla, data_ksi, mc,rok,kwota)
VALUES(@p1, SUBSTRING(@p2,@idx1,@idx2-@idx1), @p3, @p4, @p5, @p6, @p7, @p8, @p9, @p10, @p11, @p12, @p13)
SET @idx1 = @idx2 + 2;
END;
ELSE
BEGIN;
INSERT INTO projekty_koszty_rozb
(id_kosztu, id_projektu, nr_dokumentu, pozycja, id_grupy, id_rodzaju, id_typu, data_dok, data_pla, data_ksi, mc,rok,kwota)
VALUES(@p1, SUBSTRING(@p2,@idx1,LEN(@p2)+1-@idx1), @p3, @p4, @p5, @p6, @p7, @p8, @p9, @p10, @p11, @p12, @p13)
SET @idx1 = -1;
END;
END;
END;
调用该过程并将p2stringlist作为@p2:
for i := 0 to TS2.Count - 1 do
begin
p2stringlist.Add(TS2[i]);
end;
您可以通过以下方式提高速度:
Connection.StartTransaction;
尝试
//将数据发送到服务器
连接。提交;
除了
连接回滚;
结束;
aqZapisz.Connection.StartTransaction;
尝试
aqZapisz.SQL.Text:=
“插入项目中”+
"(id_kosztu,id_projektu,nr_dokumentu,pozycja,id_grupy,id_rodzaju,id_typu,data_dok)"+
‘数据解放军、数据ksi、mc、韩国、广岛)’+
'值(:p1,:p2,:p3,:p4,:p5,:p6,:p7,:p8,:p9,:p10,:p11,:p12,:p13)';
aqZapisz.Parameters.ParamByName('p1')。值:=idk;
aqZapisz.Parameters.ParamByName('p3')。值:=edtNrDok.Text;
aqZapisz.Parameters.ParamByName('p4')。值:=edtPoz.Text;
aqZapisz.Parameters.ParamByName('p5')。值:=id_grupy;;
aqZapisz.Parameters.ParamByName('p6')。值:=id_rodzaju;
aqZapisz.Parameters.ParamByName('p7')。值:=id_typu;
aqZapisz.Parameters.ParamByName('p8')。值:=DateToStr(zxDateDok.Date);
aqZapisz.Parameters.ParamByName('p9')。值:=DateToStr(zxDatePlat.Date);
aqZapisz.Parameters.ParamByName('p10')。值:=DateToStr(zxDateKsieg.Date);
aqZapisz.Parameters.ParamByName('p11')。值:=IntToStr(整数(MonthOf(zxDateKsieg.Date));
aqZapisz.Parameters.ParamByName('p12')。值:=IntToStr(整数(YearOf(zxDateKsieg.Date));
aqZapisz.Parameters.ParamByName('p13')。值:=RoundTo((StrToFloat(edtWartosc.Text)/listazaznprojektow.Count),-2);
对于i:=0到TS2。计数-1 do
开始
aqZapisz.Parameters.ParamByName('p2')。值:=TS2[i];
aqZapisz.ExecSQL;
结束;
aqZapisz.Connection.Commit;
除了
aqZapisz.Connection.Rollback;
提高;
结束;
您应该测量应用程序和服务器任务需要多长时间才能得到提示,是否值得实现(2) 对于这种情况,较新的Delphi版本有一个方便的解决方案
var
LInternal,LServer:TStopWatch;
开始
LServer:=TStopWatch.Create;
LInternal:=TStopWatch.StartNew;
...
对于i:=0到TS2。计数-1 do
开始
aqZapisz.Parameters.ParamByName('p2')。值:=TS2[i];
LServer.Start;
aqZapisz.ExecSQL;
LServer.Stop;
结束;
...
停下来;
ShowMessage(
格式(
'总计:%dms服务器:%dms',
[LInternal.elapsedmilloses,LServer.elapsedmilloses]);
结束;
您使用哪个版本的Delphi?您的数据库位于哪里(广域网或局域网)?
如果您有像XE4-XE7这样的更新版本,可以尝试使用FireDAC FDQuery
以及它的特性(提交一个带有参数数组的DBMS命令)
您的代码如下所示:
with FDQuery1 do begin
SQL.Text := 'INSERT INTO projekty_koszty_rozb ' +
'(id_kosztu,id_projektu, nr_dokumentu, pozycja,id_grupy, id_rodzaju, id_typu, data_dok, '
+ 'data_pla, data_ksi,mc,rok,kwota) ' +
'VALUES(:p1,:p2, :p3, :p4, :p5, :p6, :p7, :p8, :p9,:p10,:p11,:p12,:p13)';
// Set up parameter types
Params[0].DataType := ftInteger;
Params[1].DataType := ftString;
Params[1].Size := 40;
Params[2].DataType := ftString;
Params[2].Size := 40;
Params[3].DataType := ftString;
Params[3].Size := 40;
Params[4].DataType := ftString;
Params[4].Size := 40;
Params[5].DataType := ftInteger;
Params[6].DataType := ftInteger;
Params[7].DataType := ftInteger;
Params[8].DataType := ftString;
Params[8].Size := 40;
Params[9].DataType := ftString;
Params[9].Size := 40;
Params[10].DataType := ftString;
Params[10].Size := 40;
Params[11].DataType := ftString;
Params[11].Size := 40;
Params[12].DataType := ftString;
Params[12].Size := 40;
Params[12].DataType := ftFloat;
// Set up parameters' array size
Params.ArraySize := TS2.Count;
// Set parameter values
for i := 0 to TS2.Count - 1 do begin
Params[0].AsIntegers[i] := idk;
Params[1].AsStrings[i] := TS2[i];
Params[2].AsStrings[i] := edtNrDok.Text;
Params[3].AsStrings[i] := edtPoz.Text;
Params[4].AsIntegers[i] := id_grupy;
Params[5].AsIntegers[i] := id_rodzaju;
Params[6].AsIntegers[i] := id_typu;
Params[7].AsStrings[i] := DateToStr(zxDateDok.Date);
Params[8].AsStrings[i] := DateToStr(zxDatePlat.Date);
Params[9].AsStrings[i] := DateToStr(zxDateKsieg.Date);
Params[10].AsStrings[i] := IntToStr(Integer(MonthOf(zxDateKsieg.Date)));
Params[11].AsStrings[i] := IntToStr(Integer(YearOf(zxDateKsieg.Date)));
Params[11].AsDouble[i] := RoundTo((StrToFloat(edtWartosc.Text) / listazaznprojektow.Count), -2);
end;
// Execute batch
Execute(TS2.Count, 0);
end;
procedure AddParams(aServerSQLParams: TRemoteSerializableSQLParams; aParamName: string; aFieldType: TFieldType; aValue: Variant);
var
MyParam: TRemoteSerializableSQLParam;
begin
MyParam := TRemoteSerializableSQLParam(aServerSQLParams.AddParameter);
MyParam.Name := aParamName;
MyParam.DataType := aFieldType;
MyParam.Value := aValue;
end;
procedure SaveMyData;
var
MySerSQLParams: TRemoteSerializableSQLParams;
begin
try
RemoteSQL_Handler1.StartTransaction;
MySerSQLParams:= TRemoteSerializableSQLParams.Create;
for i := 0 to TS2.Count - 1 do begin
MySQL := 'INSERT INTO projekty_koszty_rozb ' +
'(id_kosztu,id_projektu, nr_dokumentu, pozycja,id_grupy, id_rodzaju, id_typu, data_dok, '
+ 'data_pla, data_ksi,mc,rok,kwota) ' +
'VALUES(:p1,:p2, :p3, :p4, :p5, :p6, :p7, :p8, :p9,:p10,:p11,:p12,:p13)';
AddParams(MySerSQLParams, 'p1', ftInteger, idk);
AddParams(MySerSQLParams, 'p2', ftString, TS2[i]);
AddParams(MySerSQLParams, 'p3', ftString, edtNrDok.Text);
AddParams(MySerSQLParams, 'p4', ftString, edtPoz.Text);
AddParams(MySerSQLParams, 'p5', ftInteger, id_grupy);
AddParams(MySerSQLParams, 'p6', ftInteger, id_rodzaju);
AddParams(MySerSQLParams, 'p7', ftInteger, id_typu);
AddParams(MySerSQLParams, 'p8', ftString, DateToStr(zxDateDok.Date));
AddParams(MySerSQLParams, 'p9', ftString, DateToStr(zxDatePlat.Date));
AddParams(MySerSQLParams, 'p10', ftString, DateToStr(zxDateKsieg.Date));
AddParams(MySerSQLParams, 'p11', ftString, IntToStr(Integer(MonthOf(zxDateKsieg.Date))));
AddParams(MySerSQLParams, 'p12', ftString, IntToStr(Integer(YearOf(zxDateKsieg.Date))));
AddParams(MySerSQLParams, 'p13', ftFloat, RoundTo((StrToFloat(edtWartosc.Text) / listazaznprojektow.Count), -2));
RemoteSQL_Handler1.ExecuteSQL(MySQL, MySerSQLParams);
end;
RemoteSQL_Handler1.CommitTransaction;
except
RemoteSQL_Handler1.RollBackTransaction;
FreeAndNil(MySerSQLParams);
end;
FreeAndNil(MySerSQLParams);
end;
您还可以尝试在潜在网络上更快、处理较慢性能的方法。
您的基本代码可能如下所示:
with FDQuery1 do begin
SQL.Text := 'INSERT INTO projekty_koszty_rozb ' +
'(id_kosztu,id_projektu, nr_dokumentu, pozycja,id_grupy, id_rodzaju, id_typu, data_dok, '
+ 'data_pla, data_ksi,mc,rok,kwota) ' +
'VALUES(:p1,:p2, :p3, :p4, :p5, :p6, :p7, :p8, :p9,:p10,:p11,:p12,:p13)';
// Set up parameter types
Params[0].DataType := ftInteger;
Params[1].DataType := ftString;
Params[1].Size := 40;
Params[2].DataType := ftString;
Params[2].Size := 40;
Params[3].DataType := ftString;
Params[3].Size := 40;
Params[4].DataType := ftString;
Params[4].Size := 40;
Params[5].DataType := ftInteger;
Params[6].DataType := ftInteger;
Params[7].DataType := ftInteger;
Params[8].DataType := ftString;
Params[8].Size := 40;
Params[9].DataType := ftString;
Params[9].Size := 40;
Params[10].DataType := ftString;
Params[10].Size := 40;
Params[11].DataType := ftString;
Params[11].Size := 40;
Params[12].DataType := ftString;
Params[12].Size := 40;
Params[12].DataType := ftFloat;
// Set up parameters' array size
Params.ArraySize := TS2.Count;
// Set parameter values
for i := 0 to TS2.Count - 1 do begin
Params[0].AsIntegers[i] := idk;
Params[1].AsStrings[i] := TS2[i];
Params[2].AsStrings[i] := edtNrDok.Text;
Params[3].AsStrings[i] := edtPoz.Text;
Params[4].AsIntegers[i] := id_grupy;
Params[5].AsIntegers[i] := id_rodzaju;
Params[6].AsIntegers[i] := id_typu;
Params[7].AsStrings[i] := DateToStr(zxDateDok.Date);
Params[8].AsStrings[i] := DateToStr(zxDatePlat.Date);
Params[9].AsStrings[i] := DateToStr(zxDateKsieg.Date);
Params[10].AsStrings[i] := IntToStr(Integer(MonthOf(zxDateKsieg.Date)));
Params[11].AsStrings[i] := IntToStr(Integer(YearOf(zxDateKsieg.Date)));
Params[11].AsDouble[i] := RoundTo((StrToFloat(edtWartosc.Text) / listazaznprojektow.Count), -2);
end;
// Execute batch
Execute(TS2.Count, 0);
end;
procedure AddParams(aServerSQLParams: TRemoteSerializableSQLParams; aParamName: string; aFieldType: TFieldType; aValue: Variant);
var
MyParam: TRemoteSerializableSQLParam;
begin
MyParam := TRemoteSerializableSQLParam(aServerSQLParams.AddParameter);
MyParam.Name := aParamName;
MyParam.DataType := aFieldType;
MyParam.Value := aValue;
end;
procedure SaveMyData;
var
MySerSQLParams: TRemoteSerializableSQLParams;
begin
try
RemoteSQL_Handler1.StartTransaction;
MySerSQLParams:= TRemoteSerializableSQLParams.Create;
for i := 0 to TS2.Count - 1 do begin
MySQL := 'INSERT INTO projekty_koszty_rozb ' +
'(id_kosztu,id_projektu, nr_dokumentu, pozycja,id_grupy, id_rodzaju, id_typu, data_dok, '
+ 'data_pla, data_ksi,mc,rok,kwota) ' +
'VALUES(:p1,:p2, :p3, :p4, :p5, :p6, :p7, :p8, :p9,:p10,:p11,:p12,:p13)';
AddParams(MySerSQLParams, 'p1', ftInteger, idk);
AddParams(MySerSQLParams, 'p2', ftString, TS2[i]);
AddParams(MySerSQLParams, 'p3', ftString, edtNrDok.Text);
AddParams(MySerSQLParams, 'p4', ftString, edtPoz.Text);
AddParams(MySerSQLParams, 'p5', ftInteger, id_grupy);
AddParams(MySerSQLParams, 'p6', ftInteger, id_rodzaju);
AddParams(MySerSQLParams, 'p7', ftInteger, id_typu);
AddParams(MySerSQLParams, 'p8', ftString, DateToStr(zxDateDok.Date));
AddParams(MySerSQLParams, 'p9', ftString, DateToStr(zxDatePlat.Date));
AddParams(MySerSQLParams, 'p10', ftString, DateToStr(zxDateKsieg.Date));
AddParams(MySerSQLParams, 'p11', ftString, IntToStr(Integer(MonthOf(zxDateKsieg.Date))));
AddParams(MySerSQLParams, 'p12', ftString, IntToStr(Integer(YearOf(zxDateKsieg.Date))));
AddParams(MySerSQLParams, 'p13', ftFloat, RoundTo((StrToFloat(edtWartosc.Text) / listazaznprojektow.Count), -2));
RemoteSQL_Handler1.ExecuteSQL(MySQL, MySerSQLParams);
end;
RemoteSQL_Handler1.CommitTransaction;
except
RemoteSQL_Handler1.RollBackTransaction;
FreeAndNil(MySerSQLParams);
end;
FreeAndNil(MySerSQLParams);
end;
RemoteSQL收集您的查询,压缩它们并立即(批处理)将它们发送到服务器端。执行一些大容量插入搜索。尝试使用所述的外部表,例如,此处:。它的工作速度比按一行解释数据快得多。顺便说一句,它只在服务器端工作。似乎只有参数p2被更改,除非我忽略了什么。我认为在循环之前移动除p2之外的所有参数可以使它更加高效。我测试了这两个建议-循环中的所有参数,循环中只有p2。结果=可能比旧代码好5秒,但仍然太长;(可能可以发送到sql server命令和所有参数(使用ts2)并将其插入循环中,但“在”sql server中而不通过网络传输每个插入?类似于使用for循环的存储过程…@user1762186也尝试按名称取消对参数的访问(每次Delphi在参数列表中搜索时)。将一些变量声明为
p1,p2,…:TParam;
,然后在循环p1:=aqZapisz.Parameters.ParamByName('p1')…
之前,使用p1.Value:=…
而不是aqZapisz.Parameters.ParamByName('p1')。值:=…
在循环中。值(@p1,SUBSTRING(@p2,@idx1,LEN(@str)中的“@str”是什么+1-@idx1、@p3、@p4、@p5、@p6、@p7、@p8、@p9、@p10、@p11、@p12、@p13)`因为is未声明?我尝试了第一种方法,但结果是一样的。执行代码的最长部分是for循环-它需要很长的时间:(@user1762186@str
)