如何使用like子句和变音符号过滤数据集中的字符串字段?

时间:2017-07-26 22:58:53

标签: delphi sql-like delphi-10.1-berlin tclientdataset client-side-data

虽然有一些关于数据集过滤的documentation,但只概述了语法细节。在我的应用程序中,我想用数据集过滤器过滤人名。通常情况下这很快,但我偶然发现了一个小问题过滤,例如TClientDataset。如何为变音符号添加类似的过滤器?表达式

[X] LIKE 'Ö%'

(对于给定的字段X)不起作用(与表达式[X] LIKE 'A%'不同)。这只是一个错误,还是我需要在某处设置字符集/编码?

最小的例子

procedure TForm1.FormCreate(Sender: TObject);
var
  LField: TFieldDef;
  LCDs: TClientDataSet;
const
  SAMPLE_CHAR: string = 'Ö';
begin
  LCds := TClientDataSet.Create(Self);
  LField := LCds.FieldDefs.AddFieldDef();
  LField.DataType := ftString;
  LField.Size := 10;
  LField.Name := 'X';
  LCDs.CreateDataSet;
  LCDs.Append;
  LCDs.FieldByName('X').AsString := SAMPLE_CHAR;
  LCDs.Post;

  ShowMessage(LCds.FieldByName('X').AsString);
  LCds.Filter := '[X] LIKE ' + QuotedStr(SAMPLE_CHAR + '%');
  LCds.Filtered := true;
  ShowMessage(LCds.FieldByName('X').AsString);
end;

第一个消息框显示Ö,而第二个消息框为空。如果您将SAMPLE_CHARÖ更改为A,则两个消息框都会显示A

1 个答案:

答案 0 :(得分:2)

使用ftWideString数据类型创建TWideStringField字段,而不是ftString字段,该字段在内部创建TStringField字段。 TStringField用于ANSI字符串,而TWideStringField用于Unicode字符串。这样做,否则你会丢失数据。

要访问TWideStringField值,请使用AsWideString属性。我在D 2009中进行了快速测试,当我尝试过滤数据集时,我得到了这个:

  

第一次机会异常$ 7594845D。异常类EAccessViolation   在模块中的地址4DB1E8D1处显示消息'访问冲突   ' MIDAS.DLL&#39 ;.读取地址00FC0298'。

经过测试的代码:

procedure TForm1.FormCreate(Sender: TObject);
var
  S: string;
  FieldDef: TFieldDef;
  MemTable: TClientDataSet;
begin
  S := 'Ŧĥε qùíçķ ƀřǭŵņ fôx ǰűmpεď ōvêŗ ţħě łáƶÿ ďơǥ';

  MemTable := TClientDataSet.Create(nil);
  try
    FieldDef := MemTable.FieldDefs.AddFieldDef;
    FieldDef.DataType := ftWideString;
    FieldDef.Size := 255;
    FieldDef.Name := 'MyField';

    MemTable.CreateDataSet;
    MemTable.Append;
    MemTable.FieldByName('MyField').AsWideString := S;
    MemTable.Post;

    ShowMessage(MemTable.FieldByName('MyField').AsWideString); { ← data lost }
    MemTable.Filter := '[MyField] LIKE ' + QuotedStr('%' + 'ǰűmpεď' + '%');
    MemTable.Filtered := True; { ← access violation }
    ShowMessage(MemTable.FieldByName('MyField').AsWideString);
  finally
    MemTable.Free;
  end;
end;

我希望它与您的Delphi版本无关,但是,如果可以的话,我更愿意使用FireDAC。在那里你会对Unicode字符串做同样的事情(你的代码会通过用 TFDMemTable 替换 TClientDataSet 并添加FireDAC单位来改变。)