Delphi FireDAC TFDQuery SQL Server数据时间过滤器问题

kqlmhetl  于 2022-11-04  发布在  SQL Server
关注(0)|答案(1)|浏览(272)

对于我来说,我似乎不能使用DateTime字段/格式过滤我的TFDQuery。我有一个需要从组件(cxGrid)“导入”过滤器的查询,其中包括:

  • “日期=“(日期时间字段);
  • “值=“(浮点字段);
  • “供应商=“(字符串字段);

(And其他几个,但那些是更重要的)。日期是秒敏感的,所以它有HH:MM:SS,这是必要的股票/contability的目的。
现在,我所说的“导入”过滤器是指我使用的过滤器与cxGrid上当前标记的过滤器相同。

Filter := cxGridDBTableView.DataController.Filter.FilterText;

这将为我提供该cxGrid中当前使用的所有筛选器的字符串。
然后,我将此字符串放入查询的筛选器中,如下所示:

MyTFDQuery.Filtered := False;

MyTFDQuery.Filter := Filter;

MyTFDQuery.Filtered := True;

这给Value带来了一个问题,因为我们有一个显示格式,它将浮点数更改为不同的格式(比如从2.4更改为2.40),但这个问题已经得到了解决。供应商和其他字段都像一个护身符一样工作,主要是因为它们没有掩码/显示格式。
我的问题是在运行DateTime字段(日期)筛选器时,出现以下错误:
[FireDAC][Stan][评估] -114。预期值为[]
此字段没有任何类型的显示格式或掩码。
我试着在网上搜索这个错误代码,但什么也找不到。我试着更改日期过滤器的格式,看到很多人都有格式问题。我试过所有形式的:

MyTFDQuery.Filter := 'Date = ''2021-01-01 10:00:00'''

MyTFDQuery.Filter := 'Date = {dt 2021-01-01 10:00:00}'

MyTFDQuery.Filter := 'Date = ' + Chr(39) + '2021-01-01 10:00:00' + Chr(39)

MyTFDQuery.Filter := 'Date = {CONVERT(''2021-01-01 10:00:00'', DATETIME)}

还有很多我现在想不起来的事。
并且还尝试了几种不同的日期格式......比如:

YYYY-MM-DD
YYYY-DD-MM
DD-MM-YYYY
MM-DD-YYYY

或者甚至是日期的分隔符。我试过“-”;“/”;“.”和这样的(像24. 02. 1982而不是24/02/1982)。并不断尝试不同的方法来使这个工作,用不同的组合。当我在网上搜索关于这个问题时,特别是在“如何按日期时间过滤数据集/TFDQuery”中,大多数人都被告知要使用不同的日期/日期时间格式来使其工作。似乎每个人都有不同的解决方案。
我不知道该怎么做了。这是不是像一个搜索结果所指出的那样,与区域设置有某种联系?这些设置来自哪里? Delphi IDE?FireDAC?我使用的DB?我遗漏了什么吗?
基本上,我想知道我应该使用什么格式来过滤我的TFDQuery。
感谢大家到目前为止的阅读,任何帮助都将不胜感激。我希望问题足够直接。
PS:很抱歉在提问过程中我做错了什么。英语不是我的母语,这一周真的很漫长。谢谢你的耐心。
UPDATE:我通过大量的猜测发现了这个错误。当过滤器应用于数据集时,日期时间的毫秒位被考虑在内,cxGrid组件会舍入秒数(例如,将'2021-02-01 18:05:03.822'改为'2021-02-01 18:05:04')。
这样,当Date = '2021-02-01 18:05:04'过滤一些东西时,它不会显示任何东西。这不是格式的问题,而是日期时间相等的问题。
为了解决这个问题,我听从了Brian的建议,进行了更改:
cxGridDBTableView.DataController.Filter.DateTimeFormat := 'yy-mm-dd hh:mm:ss.zzz'
现在,从过滤器中取出毫秒数,忽略舍入。不幸的是,我被它给出的误差卡住了:
[FireDAC][Stan][Eval] -118。无法将类型(Unicode字符串)的变量转换为类型(日期)
如有任何进一步的帮助,我们将不胜感激。

pjngdqdw

pjngdqdw1#

我已经找到了这个问题的“解决方案”。我只是假设查询不接受毫秒级的字符串过滤器,也许是一些兼容性问题。我把这个留在这里,希望像我这样有问题的人能快速解决它,也许其他人能改进这个问题,使它更优雅/更高效。
为了便于管理,我将字符串分解并插入到stringlist中:

MyStringListFilters.LineBreak := ' AND ';
MyStringListFilters.Text := Filter;

这会将筛选器的字符串从:

((Date = ''28/09/2022 18:22:44.789'') OR (DATE = ''11/02/2019 07:18:03.122'')) AND ((Value = 2,4) OR (Value = 7,9)) AND (SUPPLIER = ''My Supplier Name Ltda'')

收件人:

((Date = ''28/09/2022 18:22:44.789'') OR (DATE = ''11/02/2019 07:18:03.122''))
((Value = 2,4) OR (Value = 7,9))
(SUPPLIER = ''My Supplier Name Inc'')

现在,只需使用StringReplace就可以轻松地修复值:

While i < MyStringListFilters.Count do
  if (Copy(MyStringListFilters[i], 2, 5) = 'Value') or (Copy(MyStringListFilters[i], 3, 5) = 'Value') then
    StringReplace(MyStringListFilters[i], ',', '.', [rfReplaceAll]);

(When有两个或值,则字符串前面会有一个额外的括号)。
修复日期有点困难,我必须将字符串插入另一个字符串列表中,并以同样的方式将其分解:

//inside of the same while
if (Copy(MyStringListFilters[i], 2, 4) = 'Date') or (Copy(MyStringListFilters[i], 3, 4) = 'Date') then
begin
  MyStringListDates.LineBreak := ' OR ';
  MyStringListDates.Text := MyStringListFilters[i];
//it keeps on going...

它将日期字符串进一步细分为:

((Date = ''28/09/2022 18:22:44.789'')
(Date = ''11/02/2019 07:18:03.122''))

注意:如果有两个或更多的Date过滤器,我们必须删除第一个过滤器和最后一个过滤器中的括号。我们还必须设置循环结束时的状态。切记始终递增两个while的索引整数。

//This happens inside the first while...
while j < MyStringListDates.Count do
begin
  TempDate := Copy(MyStringListDates[j], 10, 19);
  //This pulls the whole second, ignoring milliseconds from the DB.
  MyStringListDates[j] := '((Date >= ' + QuotedStr(TempData) + ') and (Date < ' + QuotedStr(DateTimeToStr(IncSecond(StrToDateTime(TempData)))) + '))';
  FixedDate := FixedDate + MyStringListDates[j];
  if FixedDate = '' then
  begin
    // Puts the first parentheses back.
    if MyStringListDates.Count > 1 then
       FixedDate := '(';
       FixedDate := FixedDate + MyStringListDates[j];
   end
   else
     FixedDate := FixedDate + ' OR ' + MyStringListDates[j];
   Inc(j);
end
//Remember to add the last parentheses here, if there is more than 1 Date Filter.

我想感谢@Brian对这个解决方案的帮助。我没有注意到组件可以更改,所以DateTime会有不同的结果。
我也要感谢@marc_s编辑了原问题,这是我在平台上的第一个问题,所以我不知道自己在做什么(仍然不知道,抱歉)。
还要特别感谢@Uwe Raabe,我也用了他们的答案来解释如何使用多字符分隔符来拆分字符串。下面是他们回答的问题的链接:
How to split string by a multi-character delimiter?

相关问题