Delphi 如何使用like子句和umlaut筛选数据集中的字符串字段?

Delphi 如何使用like子句和umlaut筛选数据集中的字符串字段?,delphi,sql-like,delphi-10.1-berlin,tclientdataset,client-side-data,Delphi,Sql Like,Delphi 10.1 Berlin,Tclientdataset,Client Side Data,尽管有一些关于数据集过滤的内容,但语法细节仅作了概述。在我的应用程序中,我想用数据集过滤器过滤人名。通常情况下,这工作非常快,但我遇到了一个小问题,例如过滤TClientDataset。如何为umlaut添加一个like过滤器?表情 [X] LIKE 'Ö%' (对于给定字段X)不起作用(与表达式[X]如'a%')。这只是一个bug还是我需要在某个地方设置字符集/编码 最简单的例子: 第一个消息框显示Ö,而第二个消息框为空。如果将SAMPLE_CHAR从Ö更改为A,则两个消息框均显示A使用数据

尽管有一些关于数据集过滤的内容,但语法细节仅作了概述。在我的应用程序中,我想用数据集过滤器过滤人名。通常情况下,这工作非常快,但我遇到了一个小问题,例如过滤
TClientDataset
。如何为umlaut添加一个like过滤器?表情

[X] LIKE 'Ö%'
(对于给定字段
X
)不起作用(与表达式
[X]如'a%'
)。这只是一个bug还是我需要在某个地方设置字符集/编码

最简单的例子:

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

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

要访问值,请使用属性。我在D 2009中做了一个快速测试,当我尝试过滤数据集时,我得到了以下结果:

第一次机会例外价格为7594845D美元。异常类EAccessViolation 带有消息“模块中地址4DB1E8D1处的访问冲突” “midas.dll”。读取地址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字符串执行相同的操作(您的代码将通过将TClientDataSet替换为TFDMemTable并添加FireDAC单位来更改)。

您使用的是什么数据库?
X
字段实际使用的字符集是什么?用于访问数据库的驱动程序是否支持SQL语句中的Unicode字符?例如,SQLServer有一个Unicode字符串文本的
N
前缀,例如
[X]类似于N'Ö%”
@RemyLebeau:没有数据库。这是一个
TClientDataset
,被用作内存中的数据集。@KenWhite:好的,我错过了。在这种情况下,尝试使用
ftWideString
而不是
ftString
,也可能使用
AsWideString
而不是
AsString
@RemyLebeau。我刚刚试用了你的ftWideString解决方案(没有AsWideString),它在我的机器上运行。@Dsm也适用于我!但还有别的办法吗?我可以这样写一个过滤器而不改变整个数据集吗?显然,字符串
Ö
本身以某种方式存储在数据集中。提到内部字符串字符集是
utf-8
,但我不知道这是否适用于这里。如果
AsString
可以转换
Ö
为什么过滤器表达式中的
like
运算符不能也进行转换?好极了,另一个+1。只是一个小问题,你会考虑把你的var名字<代码>字段< /代码>改为<代码> FieldDef < /代码>吗?有一个
字段
,实际上是一个
t字段
,这会让人有点恼火。或者,您可以将
字段
设置为实际的
t字段
,然后避免调用
FieldByName
。@MartynA,谢谢!你是对的,我已经使变量名更易于解释。不过,我还是担心访问冲突。啊哈,所以这不是Unicode。那一定是过滤器的问题。它的行为很奇怪。对于ANSI字段类型,
SAMPLEÖCHAR='ÄÄÄ'
Ä%
%。它适用于
ftWideString
字段,因此我保留了原样的答案。但如果你不介意案件不敏感,这可能是一个解决办法。但这是一个MIDAS错误。@Victoria这是一个非常好的解决方案!事实上,我们使用
上限([X]),比如“+QuotedStr(SAMPLE_CHAR+'%”)
,这也不起作用。通过
focusensitive
我们有了一个可行的解决方案。
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;