主题:请教如何seek到倒数第一条记录?
moz
[专家分:37620] 发布于 2007-05-23 03:04:00
有没有更好的方法?
i=0
seek ....
do while found()
i=reccno()
continue
enddo
if i>0 goto i
又或者
set filter
goto bottom
(没有视图能用吗?)
哪个更快点?有没有更方便更高效更快的办法?用SQL好像慢很多。
最后更新于:2007-12-15 09:47:00
回复列表 (共32个回复)
11 楼
lwh1188 [专家分:25840] 发布于 2007-05-23 22:33:00
“...也就是说同一个名字下,会有不同的地址或电话或联系方式之类的东西。
我需要在下订单的时候,自动翻出最新的资料,核对一下,能用则用,要改则改。
也就是说需要同一个名字,日期最晚的一条记录,你们说该怎么找好?...”
可否求得“‘记录日期’与‘查询当天的日期’相比较的‘最小值’即为最新的记录?
12 楼
moz [专家分:37620] 发布于 2007-05-23 23:24:00
乌鸦,我不是想送分给你,
我其实是想听听DJ的建议,
我很看好这年轻人,通常都能给到我很好有用的提示与想法.
他的习惯与积极的态度,很让我有相近的感觉.
lmh说的也有道理,其实跟我考虑的问题是一样的,
我现在顾虑的问题,DJ都已经帮我实践过了,在VFP里暂时也没有什么更好的办法了.
lmh,老高, 以及大家建议用SQL再go bottom的方法都一样,
需要比较,而这个比较无法在查询或定位或查找的过程中实现,
只能在结果里再一次筛选,导致需要全部查找一次,浪费不少时间与性能.
相信大家都已经明白我的需求了: 名字相同,最后最新的一条记录
我以前在做QB代码的时候,做了一个字符串搜索子串的程序,
用以在大文件里搜索某关键字.
(说来惭愧,这个大文件正是 .dbf 文件,呵呵,因为追加的记录都会放在文件末,
而一般数据查找都是从近到远搜索的,肯定是先查昨天再上月再去年的了,
所以我就写了一个函数,以 16K 长度的字符串为单位,从文件末读入字符串,
检查是否有字串,这个检查方法当然调用系统函数的汇编代码更快了,
再将指针(脑袋中的指针)往前移(长度-关键字长度)的位置,再读入再搜索
这样子,我总能更快的得到搜索结果,而且还不需要重新排序)
现在遇到的想法也是一样的.
问题是在VFP里也是一样,没有从后面开始搜索的方法,
(字符串操作倒是有从后面开始搜索的函数)
如果能够从文件末开始搜索的话, seek 的第一条记录当然就是结果了,
可以省掉前面一大片的浪费.
如果 set order to 名字 的话,seek 也总是以 A-Z 的方向去搜索,
找到的却不一定是最新的一条记录.
如果 set order to 日期 的话,locate for 的速度又受到了限制.
(DJ说的优化查询叫什么RUN...技术,我经常能看到,但却不知道具体的操作及差别在哪)
如果说,locate for 能自动使用存在的,未 set order to 的索引,
而又能定位到以 set order to 日期 的最新的记录,目标也就实现了.
能得到大家的帮助,又能活动一下大家的脑袋,我很高兴.谢谢大家.
医学证明,常动脑,能有效避免老年痴呆症的出现,对大家也是一种收获,呵呵.
13 楼
cbl518 [专家分:57140] 发布于 2007-05-24 01:11:00
年纪大了就好强,没办法改。
兄弟:你试试看下面代码,检索最后的纪录用多长时间。
股市中的数据,检索几十亿条记录,也不过 1 秒,你相信吗?这是 vfp 的特点。
我不知道你的数据结构,不能编出更好的方法,只不过是一种思路,希望对你有帮助。
[color=0000FF]LOCAL i, n最后合乎条件的纪录, n每次搜索数
n最后合乎条件的纪录=""
n每次搜索数=10000 && [color=FF0000]根据你的数据结构,调整该参数会收到很好的效果。[/color]
FOR i=RECCOUNT()-n每次搜索数 TO 1 STEP -n每次搜索数
GO i
SCAN REST FOR 条件=.T. WHILE RECNO()<= i+n每次搜索数
n最后合乎条件的纪录= 表.字段名
ENDSCAN
IF ! EMPTY(n最后合乎条件的纪录)
EXIT
ENDIF
ENDFOR
?最后合乎条件的纪录[/color]
由于某种关系,我没测试,如果有错误,请谅解!!!
14 楼
0901chang [专家分:10660] 发布于 2007-05-24 02:53:00
moz兄,和你开玩笑。使用索引,速度非常快,下面的例子
CREA TABL 订货表 ( 标识号 N(8),姓名 C(24),订货日期 C(10),联系电话 C(20),联系地址 C(60) )
inde on str(标识号)+订货日期 tag 正排序
inde on str(标识号)+订货日期 tag 倒排序 DESCENDING
use
sele 0
use 订货表
set orde to 倒排序
m_标识号=?
seek str(m_标识号) && 定位到最后的记录
copy to 临时表 whil 标识号=m_标识号
sele 0
use 临时表 excl
brow
* 这种方法,数十万记录中,0.1秒就完成,这是VFP的优势
用此索引,执行select语句,速度应该和seek一样快。只是我很笨,一直不会用该语句。
15 楼
cbl518 [专家分:57140] 发布于 2007-05-24 06:42:00
利用倒索引方法是快,这是肯定的,但要根据具体情况用。
如果该表不常更新录入的话,可用。
否则,当数据变化一次,系统就重新更新索引,重新更新索引的时间就不言而喻了。这返而影响使用性能。所以纪录当超过一定数量时,还是不用索引。
16 楼
moz [专家分:37620] 发布于 2007-05-24 08:58:00
cbl在13楼的方法跟我在QB里用的方法是一样的,
原始,效率极低,极可能出现漫长等待的情形.
因为scan完全没有利用上索引,速度影响是很大的.
15楼的看法也不对,当你明白索引是怎样建立怎样修改怎样利用的,
你才能明白为什么我们要尽量使用索引.
无疑,建立索引是需要时间的,但快速排序比scan的速度要快得很多倍,
这就是磨刀不误砍柴工.
就算是添加修改删除记录时的重新更新索引,
那也只是单条或多条的记录的相应位置插入,
只是部份更新索引文件的内容,并不等同于reindex,
就算是reindex,时间也比scan快得多.
14楼老乌鸦的说法我早上想到了,不过有所区别,
不过要提醒你一下,SQL绝对比不上seek
建倒序索引 名字+dtoc(订货日期) **倒排序 DESCENDING
set order to 倒排序
seek 名字
问题应该能解决.
回头有时间我再试验一下.
17 楼
0901chang [专家分:10660] 发布于 2007-05-24 10:46:00
cbl518兄,vf是允许建立很多个索引的,在建表是就把索引建立,到要用时只要执行
set orde to <你的索引>
vf的索引效率非常高,我在实际应用中,有的表我建立二十多个复合索引。
你不能用
inde on ???1+??? to <索引1>
inde on ???2+??? to <索引2>
否则在 use 时你要指定打开全部索引,不然,修改数据时不更新你未打开的索引。
必须用复合索引
inde on ???1+??? tag <索引1>
inde on ???2+??? tag <索引2>
复合索引,只要你修改数据,系统就自动更新索引。
18 楼
djGong2002 [专家分:5750] 发布于 2007-05-24 10:47:00
* 自由表keyword.dbf,记录数631064,四个字段,总宽度150.
* 对字段keyword建复合结构普通索引,升序.
* 运行以下程序,找出最后一个符合条件记录.结果显示0.00秒.(没有精确计时)
* 说明 seek 比 locate for 和 select-sql快许多
CLEAR
CLEAR ALL
CLOSE ALL
t1=SYS(2)
USE keyword
SEEK "中国" ORDER tag keyword DESCENDING
t2=SYS(2)
?RECNO(),keyword,filename
?VAL(t2)-VAL(t1)
USE
RETURN
19 楼
lwh1188 [专家分:25840] 发布于 2007-05-25 22:24:00
楼上说的对,seek 确实很快,索引相当于一本图书的“目录”的页码指向,seek快在“目录”已经做好了!表索引是一个“记录号”的列表,仅与表的“记录号”有直接“关系”!应该说一般情况下,使用索引是上策!
20 楼
0901chang [专家分:10660] 发布于 2007-05-26 10:01:00
vf最优秀的就是索引,特别是可以建立多个唯一性索引,并且唯一性索引不影响非唯一性索引。
我来回复