标题:VFP 学习、开发漫谈 (28)- 顺序查询
只看楼主
liuxingang28
Rank: 11Rank: 11Rank: 11Rank: 11
来 自:山东济南
等 级:贵宾
威 望:47
帖 子:649
专家分:2156
注 册:2014-2-7
结帖率:96.77%
已结贴  问题点数:20 回复次数:11 
VFP 学习、开发漫谈 (28)- 顺序查询
在 VFP 中,记录查询大体上可分为顺序查询和索引查询。这一节课,跟大伙聊一聊顺序查询技术。

所谓顺序查询,是指按照实体表的记录号从头到尾进行查找。如果记录很少,比如:只有几条或几十条记录,则顺序查询可能比索引查询更快。

实现顺序查询的方法大致有以下几种:

一、LOCATE FOR/CONTINUE

先使用 Locate For 查找满足条件的首记录,然后再使用 Continue 遍历其他记录。

注意:Continue 与执行 Locate For 命令时所在的工作区是相关联的,在执行 Locate For 时,系统会自动将搜索条件作为该分区的一个内部属性来保存。当执行 Continue 时,系统会根据该分区保存的搜索条件向下搜索。下面的实例可以证明这一点:
程序代码:
SELECT 工资表
LOCATE FOR 实发工资>5000    && 在工资表中查找“实发工资>5000”的第一条记录
SELECT 员工表
LOCATE FOR 政治面貌="党员"  && 在员工表中查找“政治面貌="党员"”的第一条记录
SELECT 工资表
CONTINUE                    && 在工资表中查找“实发工资>5000”的下一条记录
SELECT 员工表
CONTINUE                    && 在员工表中查找“政治面貌="党员"”的下一条记录

二、SET FILTER TO/SKIP

顺序查找的第二种方法:先使用 Set Filter To 设定一个过滤条件,然后再使用 SKIP 遍历其他记录。
程序代码:
USE 工资表
SET FILTER TO 实发工资>5000
GO TOP
DO WHILE NOT EOF()
    ...
    SKIP
ENDDO

注意:在执行 SET FILTER TO 命令后,系统并不会自动将指针移动到满足条件的第一记录,因此,在 SET FILTER TO 命令后,通常要执行 GO TOP。

三、SCAN FOR

在 SCAN 命令的 FOR 条件中指定过滤条件,从而遍历所有满足条件的记录。

比如,下列代码将显示所有财务人员的基本工资和奖金:
SELECT 工资表
SCAN FOR 部门='财务部'
    ? 姓名,基本工资,奖金
ENDSCAN

四、SELECT SQL

严格来说,SELECT SQL有其独特的搜索机制,将其归为顺序查询可能并不严谨。

根据我的经验,一般来说,SELECT SQL 要比索引查询慢,但要比 LOCATE FOR/SET FILTER TO/SCAN FOR 快。在顺序查找的几种方法中,我更喜欢使用 SELECT SQL一次性将满足条件的记录筛选出来,再加工处理。

下面举一个使用 LOCATE FOR/CONTINUE 连续搜索的实例。

源代码下载:
search.rar (3.37 KB)



功能描述:
1. 在搜索框中输入姓名,回车或单击“搜索”按钮,则显示该学生的第一门课的考试成绩。
2. 再次单击“搜索”按钮,则显示该学生的下一门课的考试成绩。
3. 当显示到最后一门课的成绩,再单击“搜索”时,系统提示“未找到 XXX 的其他考试记录!”。再次单击“搜索”时,将重新从头搜索。
4. 当按下 Ctrl 键单击“搜索”按钮时,则始终是搜索满足条件的首记录(Locate For)。
5. 当修改条件后单击“搜索”按钮,则重新搜索首记录。

综上所述,系统仅使用了一个按钮就实现了“搜索首记录”和“搜索下一记录”的双重功能。如果设置了新条件或按下Ctrl键,则单击“搜索”按钮时搜索首记录,否则搜索下一条记录。

主要代码如下:

1. 在表单的 Init 事件中,新建表单属性 cSearch,用于保存搜索条件:

   THIS.AddProperty('cSearch','')

2. 搜索按钮 cmdSearch.Click 代码如下:
程序代码:
LOCAL cValue,nRec
cValue = ALLT(THISFORM.txtSearch.Value)  && 要搜索的学生姓名
IF EMPTY(cValue)                         && 检测是否输入搜索值
    MESSAGEBOX('请输入学生姓名!',48,'提示')
    THISFORM.txtSearch.SetFocus
    RETURN
ENDIF
nRec = IIF(EOF(),0,RECNO())              && 保存记录指针,用于查找不到记录时返回原记录
IF cValue == THISFORM.cSearch            && 搜索条件未更改,查找满足条件的下一记录
    CONTINUE
    IF !FOUND()
        IF nRec # 0
            GO nRec
        ENDIF
        MESSAGEBOX('未找到“'+cValue+'”的其他考试记录!',48,'提示')
        THISFORM.cSearch = ''
    ENDIF
ELSE
    LOCATE FOR 姓名 = cValue             && 搜索条件已更改,搜索满足条件的首记录
    THISFORM.cSearch = cValue            && 保存搜索条件
    IF !FOUND()
        IF nRec # 0
            GO nRec
        ENDIF
        MESSAGEBOX('未找到“'+cValue+'”的考试记录!',48,'提示')
        THISFORM.cSearch = ''
    ENDIF
ENDIF
THISFORM.Refresh                         && 显示记录

3. 搜索按钮 cmdSearch.MouseDown 代码如下,以便实现按下Ctrl键时从头搜索:
* 当按下鼠标左键和Ctrl键时,清除保存的搜索条件,以便执行后续的 Click 事件代码时,搜索首记录
IF nButton = 1 AND nShift = 2
    THISFORM.cSearch = ''
ENDIF

   注意:一次鼠标单击,会顺序触发 MouseDown、Click 和 MouseUp 三个事件,但在 Click 事件中无法判断是否按下了 Ctrl 键,只能在 MouseDown 或 MouseUp 中检测,但由于 MouseUp 在 Click 之后才触发,因此,本例中只能将代码输入在 MouseDown事件中。

4. 文本框 txtSearch.Keypress 代码如下,用于按下回车键时开始搜索:
IF nKeyCode = 13                && 按下回车键
    NODEFAULT                   && 取消默认按钮引发的操作
    THISFORM.cmdSearch.Click    && 执行搜索
ENDIF

最后再声明一点:在顺序查找时,建议通过 Set Order To 将索引关闭,这种情况下,索引不但不能加快查找速度,可能还起到反作用。


[ 本帖最后由 liuxingang28 于 2014-9-15 11:05 编辑 ]
搜索更多相关主题的帖子: 工作区 开发 技术 记录 
2014-09-15 10:28
sylknb
Rank: 4
等 级:贵宾
威 望:14
帖 子:1519
专家分:174
注 册:2006-6-3
得分:5 
不错,但“当按下鼠标左键和Ctrl键时,清除保存的搜索条件”

* 按下鼠标左键和Ctrl键时,清空保存的原条件,便于执行后续的Click事件时从头搜索
IF nButton = 1 AND nShift = 2
    THISFORM.cSearch = ''
ENDIF
实际操作好象要按shift键

[ 本帖最后由 sylknb 于 2014-9-15 11:07 编辑 ]
2014-09-15 10:52
liuxingang28
Rank: 11Rank: 11Rank: 11Rank: 11
来 自:山东济南
等 级:贵宾
威 望:47
帖 子:649
专家分:2156
注 册:2014-2-7
得分:0 
实践是检验真理的唯一标准,请再测试一遍。
下面是VFP帮助文件中有关nShift键值的截图:


泉城飞狐
2014-09-15 14:40
tlliqi
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
等 级:贵宾
威 望:204
帖 子:15453
专家分:65956
注 册:2006-4-27
得分:5 
总结到位
2014-09-15 15:28
sylknb
Rank: 4
等 级:贵宾
威 望:14
帖 子:1519
专家分:174
注 册:2006-6-3
得分:0 
我又试了一遍,按住chl点击按钮,上部的内容没有变化。表示搜索条件为空。确实如此。
2014-09-15 15:38
liuxingang28
Rank: 11Rank: 11Rank: 11Rank: 11
来 自:山东济南
等 级:贵宾
威 望:47
帖 子:649
专家分:2156
注 册:2014-2-7
得分:0 
怎么会这样?是我没有讲明白,还是你的理解有问题?

我的测试过程如下:
1. 当搜索条件为空时,系统会提示“请输入姓名!”。
2. 请在搜索框中输入“李四”,单击“搜索”按钮,系统会显示李四的数学成绩(满足条件的首记录);
3. 再次单击“搜索”,会显示李四的语文成绩(满足条件的第 2 条记录);
4. 按下Ctrl键的同时单击“搜索”按钮,则仍显示李四的数学成绩(满足条件的首记录)。
5. 如果当前显示的记录就是满足条件的首记录,则第一次按“搜索”或按下Ctrl键按“搜索”时,记录没有变化。

泉城飞狐
2014-09-15 19:54
jsddx
Rank: 2
等 级:论坛游民
帖 子:42
专家分:21
注 册:2006-4-11
得分:5 
实践出真知
2014-09-16 08:12
xs591222
Rank: 9Rank: 9Rank: 9
等 级:贵宾
威 望:28
帖 子:680
专家分:1287
注 册:2009-3-1
得分:0 
分二个按键,第一个为查找,第二个为下一个,分开处理比较好
2014-09-18 19:13
liuxingang28
Rank: 11Rank: 11Rank: 11Rank: 11
来 自:山东济南
等 级:贵宾
威 望:47
帖 子:649
专家分:2156
注 册:2014-2-7
得分:0 
以下是引用xs591222在2014-9-18 19:13:11的发言:

分二个按键,第一个为查找,第二个为下一个,分开处理比较好

说的对!在我设计的应用系统中大多数情况下也是作为两个按钮来处理的,这样用户更容易理解,但使用的思路与本例相似。

泉城飞狐
2014-09-19 08:38
ILoveVFD
Rank: 3Rank: 3
等 级:论坛游侠
威 望:3
帖 子:218
专家分:147
注 册:2015-5-2
得分:0 
篇篇精彩!
2015-05-02 12:22



参与讨论请移步原网站贴子:https://bbs.bccn.net/thread-436100-1-1.html




关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.227159 second(s), 8 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved