SQL 过滤器将我的 DBGrid 变成空白 table

SQL filter turns my DBGrid into a blank table

我正在尝试编写一段代码,如果默认值已更改,它将接受用户的输入并将其放入 SQL 语句中。

procedure TfrmHotels.btnFilterClick(Sender: TObject);
  var
    iTest, iErrorCode, iMinStars, iMaxStars, iMinCost, iMaxCost: Integer;

begin
//This is the first thing the SQL does, by filtering the entire database to show all the hotels in the area the user has selected
  with dmCoAdventure do
    begin

      qryCoAdventure.SQL.Clear;
      qryCoAdventure.SQL.Add('SELECT * FROM Hotels WHERE TownName = ' + QuotedStr(frmTowns.sTown));
      qryCoAdventure.Open;

    end;
  //If the value changes
  if (spnMinStars.Value <> 0) OR (spnMaxStars.Value <> 0) then
    begin

      if spnMinStars.Value > spnMaxStars.Value then
        begin

          ShowMessage('Min Stars can''t be higher the Max Stars.');
          Exit;

        end
      else
        begin

          iMinStars:= spnMinStars.Value;
          iMaxStars:= spnMaxStars.Value;

          with dmCoAdventure do
            begin
             //Adds the filter
              qryCoAdventure.SQL.Add('AND Stars BETWEEN ' + IntToStr(iMinStars) + ' AND ' + IntToStr(iMaxStars));

              //ShowMessage('AND Stars BETWEEN ' + IntToStr(iMinStars) + ' AND ' + IntToStr(iMaxStars));

            end;

        end;

    end;
 //If the value changes
  if (edtMinCost.Text <> '') AND (edtMaxCost.Text <> '') then
    begin
     //Test that the min value is less than the max value
      if edtMinCost.Text > edtMaxCost.Text then
        begin

          ShowMessage('Min Cost can''t be more then Max Cost.');
          Exit;

        end
      else
        begin
       //Validate that it can change to an integer
          Val(edtMinCost.Text,iTest,iErrorCode);

          if iErrorCode = 0 then
            begin

              Val(edtMaxCost.Text,iTest,iErrorCode);

              if iErrorCode = 0 then
                begin

                  iMinCost:= StrToInt(edtMinCost.Text);
                  iMaxCost:= StrToInt(edtMaxCost.Text);

                  with dmCoAdventure do
                    begin
                        //Adds the filter
                      qryCoAdventure.SQL.Add('AND CostPNight BETWEEN ' + IntToStr(iMinCost) + ' AND ' + IntToStr(iMaxCost));

                    end;

                end
              else
                begin

                  ShowMessage('Min and Max values should both be numbers.');

                end;

            end
          else
            begin

              ShowMessage('Min and Max values should both be numbers.');

            end;

        end;

    end;

end;

当我添加最小和最大星数过滤器甚至成本过滤器时,网格变为空白并且不显示任何数据。我已尝试将 'between' 更改为仅用于 '<' 或 '>' 运算符,但我仍然收到相同的效果。我的想法是,这可能与 SQL 的设置方式有关,但我的知识不足以知道我哪里出错了。

Ken White 的所有评论都是正确的。因为你显然在为如何放置而苦苦挣扎 我们所说的付诸实践,这是一个简单的示例项目 as possible 这展示了如何在 Sql 查询中正确使用参数。关注它:

  1. 创建一个新的 Delphi VCL 项目并添加到它的表单中

    • AdoConnection1,其 ConnectionString 设置为连接到您的 Sql 服务器
    • 使用 AdoConnection1 的 AdoQuery1
    • DataSource1 及其 DataSet 属性 设置为 AdoQuery1
    • DataSource 属性 设置为 DataSource1
    • 的 DBGrid1
    • 两个按钮,名为 btnCreateTable 和 btnApplyFilter,带有事件处理程序,如下面的代码所示。
  2. 编辑项目的表单以包含下面显示的代码。

  3. 编译并运行项目。

  4. 单击 btnCreateTable。它执行的 Sql 是为 Microsft Sql Server 编写的 因此,如果您使用不同的服务器类型,则可能无法 100% 正确工作。如果 sQl 语句产生异常,编辑 sCreateTable and/or sInsertRows 常量,直到两者都正确执行。如果太麻烦的话, 只需手动创建酒店 table 并手动插入行。

    一旦您拥有包含数据行的酒店 table ...

  5. 单击 btnApplyFilter

  6. 网格应该只显示第 3 行和第 4 行。如果没有,则您已经完成 出了点问题,所以请检查所有内容,修正所有错误,然后重试。

现在,仔细研究程序TForm1.ApplyFilter中的代码。

FilterSql 常量指定参数化 Sql 查询,参数为 所需的最小和最大星数: :Min 和 :Max 是这些 参数.

一旦 FilterSql 被提供给 AdoQuery1,代码就将 AdoQuery1.Prepared 设置为 True; 它所做的是将查询发送到 Sql 服务器来解析它并设置一个 执行查询;它不做的是实际执行查询。 服务器准备的查询包括最小值和最大值 "placeholders" 并且服务器期望在实际执行之前被告知这些参数的值 执行查询。这就是行

AdoQuery1.Parameters.ParamByName('Min').Value := MinStars;
AdoQuery1.Parameters.ParamByName('Max').Value := MaxStars;

最后,调用

AdoQuery1.Open

告诉服务器实际执行查询,一旦服务器执行,AdoQuery1 从服务器读取结果并将它们显示在网格中。

代码

const
  sCreateTable = 'create table Hotels(ID Int primary key, Name NVarChar(20), Stars int)';

  sInsertRows =  'insert Hotels(ID, Name, Stars) values(1, ''One'', 1)'
  +  ' insert Hotels(ID, Name, Stars) values(2, ''Two'', 5)'
  +  ' insert Hotels(ID, Name, Stars) values(3, ''Three'', 3)'
  +  ' insert Hotels(ID, Name, Stars) values(4, ''Four'', 2)';

procedure TForm1.ApplyFilter(MinStars, MaxStars : Integer);
const
  FilterSql = 'select * from Hotels where Stars between :Min and :Max';
begin
  if AdoQuery1.Active then
    AdoQuery1.Close;

  AdoQuery1.Sql.Text := FilterSql;
  AdoQuery1.Prepared := True;
  AdoQuery1.Parameters.ParamByName('Min').Value := MinStars;
  AdoQuery1.Parameters.ParamByName('Max').Value := MaxStars;

  AdoQuery1.Open;
end;

procedure TForm1.btnApplyFilterClick(Sender: TObject);
begin
  ApplyFilter(2, 3);
end;

procedure TForm1.btnCreateTableClick(Sender: TObject);
begin
  AdoConnection1.Execute(sCreateTable);
  AdoConnection1.Execute(sInsertRows);
end;