尝试从 pascal 执行查询时出现异常
Exception when trying to execute a query from pascal
以下函数从网格中获取 cuits(cuit 类似于社会安全号码)并将它们插入临时 table。我正在使用 Delphi XE7 和 Firebird 2.5。
function TfImportFileARBARetenPercep.fxListClientFromGrid(
pboClient: Boolean): WideString;
var
wsAux : WideString;
stTable, stCuit: String;
qCliProv, qCuitsExcl, qCuit : TFXQuery;
niRow : Integer;
begin
wsAux := '';
qCuitsExcl.SQL.Text := 'Create global temporary table TempExcl (cuitExcl varchar(13)) on commit delete rows';
qCuitsExcl.ExecSQL;
if pboClient then
begin
stTable := 'Client'
end
else
begin
stTable := 'Prov';
end;
for niRow := 1 to gDetails.RowCount - 1 do
if Trim(gDetails.Cells[3,niRow]) <> '' then
Begin
stCuit := QuotedStr(Trim(gDetails.Cells[3,niRow]));
qCuit.SQL.Text := 'Insert into TempExcl(:cuitExcl)';
qCuit.ParamByName('cuitExcl').AsString := stCuit;
qCuit.ExecSQL;//←←←←←←←←←←←←←←←←this line throws the exception
End;
qCuitsExcl.SQL.Text :='';
qCuitsExcl.SQL.Text := 'commit;';//to commit previous inserts
qCuitsExcl.SQL.Add('drop table TempExcl;');//in case the table is not deleted when the connection is closed
qCuitsExcl.SQL.Add('commit;');//commit previous drop
qCuitsExcl.ExecSQL;
//the rest of the code only returns the list of cuits that were loaded
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
try
qCliProv.SQL.Text :=
' Select Code' +
' From ' + stTable +
' Where Active = 1 ';
if gDetails.RowCount > 0 then
begin
qCliProv.SQL.Add('And Cuit Not In (Select cuitExcl from TempExcl)');
end;
qCliProv.Open;
wsAux := '';
while not qCliProv.Eof do
begin
wsAux := wsAux + iif((wsAux = ''), '', ',') + qCliProv.FieldByName('Code').AsString;
qCliProv.Next;
end;
Result := wsAux;
finally
FreeAndNil(qCliProv);
FreeAndNil(qCuit);
FreeAndNil(qCuitsExcluidos);
end;
end;
尝试执行行 qCuit.ExecSQL;
时抛出以下异常:
Project ERP.exe raised exception class EIBNativeException with message
'[FireDAC][Phys][FB] Dynamic SQL Error SQL error code = -104 Token
unknown - line 1, column 27 ?'.
不知道为什么会抛出这个异常
问题是这是错误的:
qCuit.SQL.Text := 'Insert into TempExcl(:cuitExcl)';
这将生成一个查询:
Insert into TempExcl(?)
这是一个语法错误(“Token unknown”),因为 Firebird 不希望这个位置有问号(参数占位符),它需要标识符(列名).
一个有效的查询是:
Insert into TempExcl (cuitExcl) values (?)
或:
Insert into TempExcl values (?)
首选第一种形式,因为您明确指定了列,但在这种情况下并不是真正必要的,因为 table 无论如何都有一列。
换句话说,你需要使用:
qCuit.SQL.Text := 'Insert into TempExcl (cuitExcl) values (:cuitExcl)';
顺便说一句,我不熟悉 Delphi 或准备查询的方式和时间,但最好将此语句移出循环,因此它只准备一次(在每当 qCuit.SQL.Text
被赋值时,case Delphi 都会再次准备语句。
评论"//万一关闭连接时table没有被删除"似乎表示对Global Temporary Tables的理解不足.它们旨在成为永久对象,可供您的应用程序重复使用。也就是说,on commit delete rows
使内容仅对您当前的事务可用,而 on commit preserve rows
将使内容对您连接的其余部分(且仅您的连接)可用,并在连接关闭时删除数据。在多次执行的内容中创建和删除 GTT 表明您的设计存在问题。
以下函数从网格中获取 cuits(cuit 类似于社会安全号码)并将它们插入临时 table。我正在使用 Delphi XE7 和 Firebird 2.5。
function TfImportFileARBARetenPercep.fxListClientFromGrid(
pboClient: Boolean): WideString;
var
wsAux : WideString;
stTable, stCuit: String;
qCliProv, qCuitsExcl, qCuit : TFXQuery;
niRow : Integer;
begin
wsAux := '';
qCuitsExcl.SQL.Text := 'Create global temporary table TempExcl (cuitExcl varchar(13)) on commit delete rows';
qCuitsExcl.ExecSQL;
if pboClient then
begin
stTable := 'Client'
end
else
begin
stTable := 'Prov';
end;
for niRow := 1 to gDetails.RowCount - 1 do
if Trim(gDetails.Cells[3,niRow]) <> '' then
Begin
stCuit := QuotedStr(Trim(gDetails.Cells[3,niRow]));
qCuit.SQL.Text := 'Insert into TempExcl(:cuitExcl)';
qCuit.ParamByName('cuitExcl').AsString := stCuit;
qCuit.ExecSQL;//←←←←←←←←←←←←←←←←this line throws the exception
End;
qCuitsExcl.SQL.Text :='';
qCuitsExcl.SQL.Text := 'commit;';//to commit previous inserts
qCuitsExcl.SQL.Add('drop table TempExcl;');//in case the table is not deleted when the connection is closed
qCuitsExcl.SQL.Add('commit;');//commit previous drop
qCuitsExcl.ExecSQL;
//the rest of the code only returns the list of cuits that were loaded
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
try
qCliProv.SQL.Text :=
' Select Code' +
' From ' + stTable +
' Where Active = 1 ';
if gDetails.RowCount > 0 then
begin
qCliProv.SQL.Add('And Cuit Not In (Select cuitExcl from TempExcl)');
end;
qCliProv.Open;
wsAux := '';
while not qCliProv.Eof do
begin
wsAux := wsAux + iif((wsAux = ''), '', ',') + qCliProv.FieldByName('Code').AsString;
qCliProv.Next;
end;
Result := wsAux;
finally
FreeAndNil(qCliProv);
FreeAndNil(qCuit);
FreeAndNil(qCuitsExcluidos);
end;
end;
尝试执行行 qCuit.ExecSQL;
时抛出以下异常:
Project ERP.exe raised exception class EIBNativeException with message '[FireDAC][Phys][FB] Dynamic SQL Error SQL error code = -104 Token unknown - line 1, column 27 ?'.
不知道为什么会抛出这个异常
问题是这是错误的:
qCuit.SQL.Text := 'Insert into TempExcl(:cuitExcl)';
这将生成一个查询:
Insert into TempExcl(?)
这是一个语法错误(“Token unknown”),因为 Firebird 不希望这个位置有问号(参数占位符),它需要标识符(列名).
一个有效的查询是:
Insert into TempExcl (cuitExcl) values (?)
或:
Insert into TempExcl values (?)
首选第一种形式,因为您明确指定了列,但在这种情况下并不是真正必要的,因为 table 无论如何都有一列。
换句话说,你需要使用:
qCuit.SQL.Text := 'Insert into TempExcl (cuitExcl) values (:cuitExcl)';
顺便说一句,我不熟悉 Delphi 或准备查询的方式和时间,但最好将此语句移出循环,因此它只准备一次(在每当 qCuit.SQL.Text
被赋值时,case Delphi 都会再次准备语句。
评论"//万一关闭连接时table没有被删除"似乎表示对Global Temporary Tables的理解不足.它们旨在成为永久对象,可供您的应用程序重复使用。也就是说,on commit delete rows
使内容仅对您当前的事务可用,而 on commit preserve rows
将使内容对您连接的其余部分(且仅您的连接)可用,并在连接关闭时删除数据。在多次执行的内容中创建和删除 GTT 表明您的设计存在问题。