【问题标题】:How do I search for a field in an ado database in delphi with a sql query?如何使用 sql 查询在 delphi 的 ado 数据库中搜索字段?
【发布时间】:2023-03-26 08:43:01
【问题描述】:

我试图通过 delphi 上的 ado 数据库表进行过滤。

我有一个连接到查询 (qryData) 的 dbgrid,只要执行此代码,dbgrid 就会变为空白,并且不会再发生任何事情。即使我输入了一个有效的字段名称,它也应该在 dbgrid 中显示它,但它什么也不显示。我做错了什么?

procedure TfrmProjects.cbxColumnsSelect(Sender: TObject);
begin
if edtsearch.Text = '' then
    begin
      showmessage('The search field should be entered');
      exit;
    end
else
    begin
        ssearch:= edtsearch.Text;
        showmessage(ssearch);
    end;

 if cbxColumns.ItemIndex = -1 then
  begin
    showmessage('Please select a field');
    exit;
  end
 else
  begin
    scolumn:= cbxColumns.Items[cbxColumns.itemindex];
    showmessage(scolumn);
  end;

with dmUsers do
begin
  with qryData do
    begin
      sql.Clear;
      sql.Text := 'Select * FROM tbl_projects where' + quotedstr(scolumn) + ' = ' +quotedstr(ssearch);
      open;
    end;
end;

【问题讨论】:

  • 抱歉我的代码块不太整齐
  • “过滤器”可能不是您想要做的事情的正确词。只是要明确一点:您要做的是让用户从组合框中选择用户希望搜索的关联表中的列,提示用户在表列中匹配一个值,然后执行一个 Sql 查询来查找与查询匹配的表行?
  • @user2595912 : ... where' + quotedstr(scolumn) 将变为 ... where"xyfield" 如您所见,where"xyfield" 之间没有空格!
  • MySQL 不是 SQL Server

标签: mysql sql sql-server delphi delphi-7


【解决方案1】:

以下内容对我有用。您需要将对 qryData 的引用更改为 dmUsers.qryData。顺便说一句,尽量避免使用“with ...”

请注意,您正在构建的 SQL 并不理想,因为它没有考虑要搜索的列是否属于需要将查询中指定的值括在引号中的数据类型。列名不需要用引号引起来,但如果它有嵌入的空格,则可能需要用方括号 [ ] 括起来。您在列名周围包含引号的事实是网格变为空白的原因 - 您向服务器上的 Sql 搜索引擎询问的是“一个字符串”=“另一个字符串”的所有行,这对于任何行都是错误的所以没有返回。顺便说一句,这与 Sql 示例有关,您有时会看到其中有一个 where 子句,如 'where 1 = 2';当然,这绝不是真的,其想法是强制搜索引擎解析查询而不返回任何行。

正如@mostkito-x 评论的那样,原始查询版本的主要问题之一是查询元素之间缺少空格 大量使用空格,这样您就可以看到自己在做什么。当您遇到查询问题时,将其文本放入表单上的备忘录(设置为像 Courier 这样的固定间距字体)并没有坏处,这样您就可以观察您是否真的在构建您认为的查询.

顺便说一句,如果您没有收集到,在字符串数据类型的搜索值周围使用 QuotedStr 具有正确处理搜索值具有嵌入引号的情况(如 o'Reilly)的优势。

procedure TForm1.CbxColumnNameClick(Sender: TObject);
//  NOTE: The following code assumes that either qryData is open when it is called
//        or has persistent TFields defined
var
  FieldName,
  ValueToSearch,
  Sql : String;
  UseQuotedValue : Boolean;
begin
  FieldName := cbxColumnName.Text;
  if FieldName = '' then begin
    ShowMessage('No field selected for search.');
    Exit;
  end;

  UseQuotedValue := qryData.FieldByName(FieldName).DataType in [ftString, ftWideString, ftMemo];

  ValueToSearch := edtSearch.Text;
  if  UseQuotedValue then
    ValueToSearch := QuotedStr(ValueToSearch);

  Sql := 'select * from tblProjects where ' + FieldName + ' = ' + ValueToSearch;

  if qryData.Active then
    qryData.Close;
  qryData.SQL.Text := Sql;
  qryData.Open;
end;

此外,这种类型的查询还会读取“SQL 注入”恶意软件风险 (http://en.wikipedia.org/wiki/Sql_injection)。公认的智慧是降低这种风险的一种措施是使用参数化查询。不幸的是,对于您的任务,虽然您可以指定要匹配的列值作为参数,但您不能在 ADO 中参数化列 name

要使用参数化查询,Sql 看起来像

Select * from tblProjects where SomeColumn = :somevalue

然后,在 IDE 对象检查器中,您需要在 qryData 上定义一个参数,并且在执行查询之前,执行 qryData.Parameters.ParamByName('somevalue').Value := edtSe​​arch.Text。但是,就像我说的,你不能参数化要搜索的列名。

【讨论】:

  • +1 你提到的好:try and avoid using "with ..."。您还应该提到,查询通常是由于指令之间的空间不足而失败。如果您查看完成的sqlquery,则大多是错误的。
  • @moskitox,好的,我马上更新我的答案。
  • 请调整您的示例并显示参数的用法,否则不 +1 ;)
  • @whosrdaddy:实际上,关于参数的那一点是有意为之的,而不是 OP 真正要问的。
  • 同意,但只有一种安全方式。我为您提到 SQL 注入而鼓掌,但为了将来参考,最好将参数用法合并到示例中,以便其他用户可以学习如何以正确的方式进行... :)
【解决方案2】:

据我所知,问题出在这一行:

sql.Text := 'Select * FROM tbl_projects where' + quotedstr(scolumn) + ' = ' +quotedstr(ssearch);

应该是:

sql.Text := 'Select * FROM tbl_projects where ' + scolumn + ' = ' +quotedstr(ssearch);

第一个 QuotedStr 用常规单引号引用列名,这将匹配两个字符串值 - 一个等于列名,另一个等于搜索字符串。

如果您在列名中使用空格,则应使用适当的字符将其括起来。例如,在 MySql 中你应该使用:

sql.Text := 'Select * FROM tbl_projects where `' + scolumn + '` = ' +quotedstr(ssearch);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-02-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-30
    • 2021-04-11
    相关资源
    最近更新 更多