首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >有办法让德尔福的FireDAC识别FireDAC生成的PostgreSQL位置参数吗?

有办法让德尔福的FireDAC识别FireDAC生成的PostgreSQL位置参数吗?
EN

Stack Overflow用户
提问于 2019-07-08 16:13:06
回答 2查看 1.4K关注 0票数 2

我正在使用本机FireDAC Postgres驱动程序使用命名参数执行从PostgreSQL 11到FireDAC 11的查询。在准备语句期间,FireDAC将命名参数转换为位置参数,这是正确的。但是,如果我随后尝试为这些参数赋值,FireDAC将抛出一个“参数超出范围”的异常。FireDAC似乎不识别它生成的位置参数。例如,如果原始SQL文本如下所示:

代码语言:javascript
复制
SELECT * FROM account WHERE accountid = :accid;

在调用FDQuery的准备方法后,FireDAC将此查询转换为:

代码语言:javascript
复制
SELECT * FROM account WHERE accountid = $1;

但是,当我试图给参数赋值时,我会得到错误。该任务如下所示:

代码语言:javascript
复制
FDQuery1.Params[0].AsString = strID;

其中strID是字符串值,accountid是文本字段。此外,如果我使用类似于下面的内容,它将返回0。

代码语言:javascript
复制
ShowMessage( IntToStr( FDQuery1.Params.Count ) );

我已经大大简化了这段代码,但问题是一样的。如何让FireDAC识别它生成的位置参数?

更新:正如我所提到的,上面的代码已经大大简化了。实际上,在我们的框架中,我们有一组例程将值赋值给FireDAC宏,然后通过准备查询并读取FDQuery的Text属性来生成SQL语句。然后将该SQL语句分配给另一个FDQuery的FDQuery属性(也是动态创建的),查询就是在那里失败的。因此,下面是代码内部发生的事情的一个非常简单的例子:

代码语言:javascript
复制
var
  Query: TFDQuery;
begin
  Query := TFDQuery.Create( nil );
  Query.Connection := PGConnection;
  // In reality, the SQL statement below was generated earlier,
  // from a function call where the SQL was created by the FireDAC
  // SQL preprocessor, as opposed to being a literal expression
  Query.SQL.Text := 'SELECT * FROM tablename WHERE field2 = $1;';
  Query.Params[0].AsString := '4'; // BANG! Argument out of range

我认为这可能是由于FireDAC宏展开造成的,所以我在实例化FDQuery之后添加了以下两行:

代码语言:javascript
复制
Query.ResourceOptions.MacroCreate := False;
Query.ResourceOptions.MacroExpand := False;

不是的。这也是有帮助的。我猜FireDAC根本不认识到$1在PostgreSQL中是一个有效的位置参数。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-07-11 20:55:51

好的,也许有一种使用FireDAC属性来解决这个问题的方法,但是我还没有找到它。但是,对于这种特殊情况,即SQL是在一个方法中准备的,然后在另一个方法中分配给不同的FDQuery,我已经找到了一个答案。由于PostgreSQL允许命名参数使用数字,例如:1,我所做的就是用:字符替换$字符。如图所示

代码语言:javascript
复制
var
  SQLStmt: String;
  FDQuery: TFDQuery;
begin
  SQLStmt :=  'SELECT * FROM tablename WHERE field2 = $1;';
  FDQuery := TFDQuery.Create( nil );
  FDQuery.Connection := FDConnection1;
  FDQuery.SQL.Text := SQLStmt.Replace( '$', ':' );
  FDQuery.Params[0].AsString := 'SomeValue'); // Works!
  ...

而且,如果查询包含多个命名参数的实例,则FireDAC将其替换为相同的数字。

如果我找到了另一个解决方案,我会发布它。如果其他人想出了一个使用FireDAC属性的解决方案,我将选择这个答案作为正确的答案。

票数 1
EN

Stack Overflow用户

发布于 2019-07-10 15:08:05

您需要将符号参数标识符(在您的例子中是:accid)放在SQL.Text字符串中,而不是位置代码($1)中。

我刚刚测试了这两个变体。第一种有效,第二种无效。

代码语言:javascript
复制
var
  MyQ : tfdquery;
begin
  MyQ := Tfdquery.Create(nil);
  MyQ.Connection := dm1.dbMain;
  MyQ.SQL.Text := 'Select * from person where lastname = :lname;';
  MyQ.Params[0].AsString := 'Brodzinsky';
  MyQ.Open();
  ShowMessage('Records found = '+MyQ.RecordCount.ToString);
  MyQ.Close;
  MyQ.Free;
end;

下一个尝试使用位置。当然,FireDac没有看到冒号,所以不知道要创建一个参数

代码语言:javascript
复制
var
  MyQ : tfdquery;
begin
  MyQ := Tfdquery.Create(nil);
  MyQ.Connection := dm1.dbMain;
  MyQ.SQL.Text := 'Select * from person where lastname = $1;';
  MyQ.Params[0].AsString := 'Brodzinsky';
  MyQ.Open();
  ShowMessage('Records found = '+MyQ.RecordCount.ToString);
  MyQ.Close;
  MyQ.Free;
end;

在第一种情况下,person表中的11条记录以我的姓氏返回;在第二种情况下,将生成超出范围错误的参数,因为SQL文本中没有指定任何参数。注意:我正在访问一个MySQL数据库,但这里的问题是Delphi & FireDac对发送到db服务器的代码进行预处理。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56938847

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档