【问题标题】:Use TQuery.Locate() function to find other then first matching使用 TQuery.Locate() 函数查找其他然后首先匹配
【发布时间】:2018-01-25 13:40:31
【问题描述】:

Locate 将光标移动到与指定的一组搜索条件匹配的第一行。 假设qTQuery 组件,它通过TAGTAGTEXT 两列连接到数据库。使用下一个代码,我收到信 a。我想使用Locate() 函数来获取字母d

 If q.Locate('TAG','1',[loPartialKey]) Then
  begin
    tag60 := q.FieldByName('TAGTEXT');
  end

例如,如果我有这样的表:

TAG | TAGTEXT
+---+--------+
| 1 | a      |
+---+--------+
| 2 | b      |
+---+--------+
| 3 | c      |
+---+--------+
| 1 | d      |
+---+--------+
| 4 | e      |
+---+--------+
| 1 | f      |
+---+--------+

是否可以在表中找到第二次第一个出现的时间?

编辑

我的工作是找到 TAG1 的出现(我需要的出现取决于我得到的参数),我需要遍历表并从所有 TAGTEXT 字段中获取值,直到找到TAG字段中的值又是数字1。在这种情况下,数字1代表新段的开始,两个数字1之间的所有数字都属于一个段。 每个段中的行数不必相同。此外,我不允许对表格进行任何更改。

我想我可以做的是创建一个计数器变量,每次到达 TAG 时都会增加一,其中的值为 1。当计数器等于代表事件的参数时,我知道我在正确的段中,我将遍历该段并获得我需要的值。 但这可能是一个缓慢的解决方案,我想知道是否有更快的解决方案。

【问题讨论】:

  • 为什么不直接从 SQL 查询中执行此操作?
  • 也许使用Filter
  • 2 qs: a) 你使用什么数据库后端? TQuery 用于 BDE,它已经过时了二十年。 b)您的表是否包含一列,该列标识属于同一行块的条目,例如段ID?如果没有,您应该添加一个。
  • @nikname 如果您需要找到第 55 次出现,那应该是您问题的一部分。
  • 类似于this question

标签: sql-server delphi delphi-2006 bde


【解决方案1】:

你需要对使用Locate 来达到这样的目的有点警惕,因为有些 TDataSet 后代对 Locate(或底层 db-access 层)的实现在数据集上构建了一个临时索引。它可以在之后立即被丢弃,因此重复调用Locate 来迭代给定段的行可能比人们预期的效率低得多。

另外,TClientDataSet 为每次调用Locate(在其对LocateRecord 的内部调用)构造、使用然后丢弃一个表达式解析器,这对于重复调用来说是很多开销,特别是当它们完全被调用时可以避免的。

在任何情况下,最好的方法是确保您的表记录给定行所属的段,如果您的表还没有列,请在下面添加SegmentID 之类的列:

TAG | TAGTEXT|SegmentID
+---+--------+---------+
| 1 | a      |     1
| 2 | b      |     1
| 3 | c      |     1
| 1 | d      |     2
+---+--------+---------+  // btw, what happened to the 2 missing rows after this one?
| 4 | e      |     2
| 1 | f      |     3
+---+--------+---------+

然后,您可以使用这样的代码来迭代段的行:

procedure IterateSegment(Query : TSomeTypeOfQueryComponent; SegmentID : Integer);
var
  Sql; String;
begin
  Sql := Format('select * from mytable where SegmentID = %d order by Tag', [SegmentID]);
  if Query.Active then
    Query.Close;
  Query.Sql.Text := Sql;

  Query.Open;

  Query.DisableControls;
  try
    while not Query.Eof do begin
      //  process row here
      Query.Next;
    end;
  finally
    Query.EnableControls;
  end;

end;

一旦你在表中有SegmentID列,如果你不想打开一个新的查询来迭代一个块,你可以设置一个本地索引(通过SegmentID然后Tag),假设您的数据集类型支持它,在数据集上设置一个过滤器以将其限制为给定的SegmentID,然后对其进行迭代

【讨论】:

  • 感谢您的回答,但这并不能解决我的问题。首先,我不允许添加列SegmentID。其次,没有遗漏的行,我已经简化了这个表,但在实际表中TAG 列中的值是数字和字母的组合。例如,这里的数字 1 是真实表中的:21R。而且我不能保证该标签的两次出现之间有多少行(可能不同)。
  • @nikname:好吧,即便如此,你需要做的还是很简单的。我今天早上很忙,但稍后会尝试发布有关它的更新。
  • 谢谢。再次查看我的问题,我已根据我的解决方案建议对其进行了编辑。看看那个好不好。
【解决方案2】:

您有很多选择。

如果您的组件不提供 locateNext,您可以将您的 on 函数设为 locateNext,比较值并进行 next 直到找到。

你也可以带上带order by的sql,然后使用locate for de第一个值,测试下一个值是否匹配。

如果您使用 clientDataset,您可以过滤到组件过滤器属性中,或者将 IndexFieldNames 设置为排序值,而不是之前建议中 sql 的“排序依据”。

您也可以在 SQL Where 子句中过滤它。

【讨论】:

  • 请根据我的问题检查我的 cmets,如果可以的话,请帮助我。谢谢!
  • @nikname 您想要第 55 个标签 1 和第 56 个标签 1 之间的所有匹配项?
  • 它并不总是第 55 次出现,这取决于我得到的参数,所以它可能是任何其他出现。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-28
  • 2016-05-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多