【问题标题】:DBGrid / DataSet fails to sort as per sql statement set in CommandTextDBGrid / DataSet 无法按照 CommandText 中设置的 sql 语句进行排序
【发布时间】:2016-10-18 16:55:41
【问题描述】:

我在我正在使用的DataSetCommandText 属性中使用以下内容:

SELECT *
FROM table_name
ORDER BY FIELD(priority, 'urgent', 'normal'),
         FIELD(state, 'wait', 'executed', 'done')

它应该对我在连接到此DataSetDBGrid 中显示的数据进行排序,如下所示:

    1. priority 列中包含 urgent 的行应启动 DBGrid 列表。
    2. 那么列表应该继续在priority 列中标记为normal 的列表,
    1. 紧随其后的是state 列中标记为wait 的那些,
    2. 后面是state 列中标记为executed 的那些,
    3. 最后,列表以state 列中标记为done 的列表结束。

但它没有,实际上它确实有点,但它实际上是倒退的。 这是我制作的快速视频,向您展示正在发生的事情,也许您可​​以通过这种方式获得更清晰的视图:

Video of what's happening

我猜这是因为我正在使用的 ID columnDate column 但如果是这样,我不知道如何以及为什么。

这就是这两列的外观/设置方式:

  • ID 列设置为 Primary 和 Unique 和 Auto_Increment - 就是这样,没有索引或任何其他选项 如果不是这 2 列的问题,那么可能是 DBGrid?

我正在使用 RAD Studio 10 Seattle、dbExpress 组件(TSimpleDataSet 等)和 MySQL db

关于如何解决这个问题的任何想法?谢谢!

【问题讨论】:

  • 我之前在MySql中没用过Field(,但是好像你用错了。Field(函数的第一个参数必须是整数。你不显示有没有字段称为优先级或状态,但我猜你这样做,否则sql会失败。这与Delphi无关。
  • @nolaspeaker 我有名为优先级和状态的列,这些列的单元格值如上所述(紧急、正常、等待等)。名为 priority 和 state 的列确实设置为 VarChar,列 ID 设置为 INT - 你说这可能是问题所在,我正在使用的字段中的第一列应该是 INT(在这种情况下,优先级? )
  • 建议你阅读一下Field函数的使用方法。
  • 您的查询在 mysql management studio 中运行正常吗?插入新记录后是否刷新数据集?
  • 顺便说一句,我会将优先级和状态的类型更改为整数(根据排序要求),并为它们创建索引(单索引和双索引)。

标签: mysql sql delphi sql-order-by dbgrid


【解决方案1】:

按照自己的方式去做,让生活变得不必要地困难。

没有必要让服务器进行排序(通过使用 ORDER BY 子句,并且可以说在客户端而不是在服务器上进行排序更好,因为客户端通常有空闲的计算能力而服务器可能不会。

所以,这是我建议的解决方法:

  1. 从您的 SQL 中删除 ORDER BY,然后执行 SELECT * [...]。

  2. 将您的 SimpleDataSet 替换为 ClientDataSet 并在其上定义持久 TField。进行此更改的原因是为了能够创建两个 fkInternalCalc 类型的持久字段。

  3. 在 Object Inspector 的 TFields 编辑器中,定义两个 fkInternalCalc 字段,称为 PriorityCode 和 StateCode。

  4. 将数据集的 IndexFieldNames 属性设置为“PriorityCode;StateCode”。

  5. 在数据集的 OnCalcFields 事件中,计算 PriorityCode 和 StateCode 的值,这将给出您希望数据行具有的排序顺序。

类似:

procedure TForm1.ClientDataSet1CalcFields(DataSet: TDataSet);
var
  S : String;
  PriorityCodeField,
  StateCodeField : TField;
  iValue : Integer;
begin
  PriorityCodeField := ClientDataset1.FieldByName('PriorityCode');
  StateCodeField := ClientDataset1.FieldByName('StateCode');
  S := ClientDataset1.FieldByName('Priority').AsString;
  if S = 'urgent' then
    iValue := 1
  else
    if S = 'normal' then
      iValue := 2
    else
      iValue := 999;
  PriorityCodeField.AsInteger := iValue;

  S := ClientDataset1.FieldByName('State').AsString;
  if S = 'wait' then
    iValue := 1
  else
    if S = 'executed' then
      iValue := 2
    else
      if S = 'done' then
        iValue := 3
      else
        iValue := 999;
  StateCodeField.AsInteger := iValue;

end;

实际上,如果您避免使用FieldByName 并仅使用 OI 的 Tfields 编辑器创建的字段,会更好(更快,更少开销),因为这些字段会自动绑定到 ClientDataSet 的数据字段。已打开。

顺便说一句,记住虽然 TClientDataSet 不能在 TFields 编辑器中定义为 Calculated 的字段上排序,但它可以InternalCalc 字段上排序。

【讨论】:

  • "It's not necessary to get the server to do the sorting"。如果数据库中有数百万条记录怎么办?您还会将SELECT * 获取到客户端并在那里进行排序吗?您的解决方案/建议可能适用于 OP,但它不能回答问题。
  • @kobik:好吧,用户很快就会发现 SimpleDataSet/ClientDataSet 无论如何都无法处理这么多记录;=)
  • @MartynA,这就是我的观点。您无需将 所有 记录获取到客户端(使用任何类型的数据集)。应该在服务器端使用某种分页机制。无论如何,OP 将决定什么对他最有利...
  • @kobik:很好。我假设没有 WHERE 子句是因为从 OP 的其他 qs 中可以明显看出他刚刚开始设置他的数据库。
  • @kobik - 它不会变得那么大,可能几百(几天)..这是一个订单数据库,所以新订单会进来旧订单会出去(删除)以每日/每周为基础。因此,作为粗略估计,订单不超过 1 周。我正在使用另一个相同的表,我只会将每个订单存储为存档,但我不会对其进行任何排序或其他操作,因为我不会使用它(在极少数情况下查找旧订单)就是这样)
猜你喜欢
  • 1970-01-01
  • 2012-05-25
  • 2016-11-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多