DBGrid / DataSet无法按照CommandText中设置的sql语句进行排序

时间:2016-10-18 16:55:41

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

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

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

它应该对与DBGrid相关联的DataSet中显示的数据进行排序,如下所示:

    1. urgent列中包含priority的行应该启动DBGrid列表。
    2. 然后该列表应继续使用normal列中标记为priority的列表,
    1. 后跟wait列中标记为state
    2. 后跟executed列中标记为state
    3. 最后,列表以done列中标记为state的列表结束。
  1. 但事实并非如此,但它确实是倒退的。 这是一个快速视频,我已经向您展示了发生了什么,也许您可​​以通过这种方式获得更清晰的视图:

    Video of what's happening

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

    这就是设置这两个列的方式:

    enter image description here

    • ID列设置为Primary和Unique以及Auto_Increment - 就是它,没有Index或任何其他选项 如果问题不是那2列,那么可能是DBGrid?

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

    有关如何解决此问题的任何想法?谢谢!

1 个答案:

答案 0 :(得分:1)

你正在以不自觉的方式让生活变得不必要。

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

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

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

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

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

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

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

  6. 类似的东西:

    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编辑器创建的Fields字段会更好(更快,更少开销),因为它们会自动绑定到ClientDataSet的数据字段当它被打开时。

    顺便说一下,记住虽然TClientDataSet不能在TFields编辑器中定义的字段Calculated上排序,但它可以在{{1}上排序,这很有用。 } field。