注册 登录
编程论坛 VFP论坛

如何提高程序运行速度

fdqzy 发布于 2020-09-12 19:40, 7643 次点击
我总习惯用FOR-ENDFOR编写统计代码,在几十个字段、不到1000行的代码中,对1000左右记录统计要运行20-30分钟,对3万条记录统计要运行几个小时(至少3个小时)。不知有何好的建议改进,谢谢!
61 回复
#2
厨师王德榜2020-09-12 20:01
如果可能的话,多用数组。在内存中处理不耗用I/O,应该会快很多。
由于没有看到你的数据和意图,只能这么给你建议。
#3
fdqzy2020-09-12 20:57
例如下表
只有本站会员才能查看附件,请 登录

对_1d,_1x,_1t上下记录统计,上下记录相同字段连续,则_1dxx, 否则_1dxxf

FOR i=2 TO RECCOUNT()
GO i
SKIP -1
k_1d=_1d
k_1x=_1x
k_1t=_1t
GO i
REPLACE _1dxx WITH '_1DXX' FOR '_'$k_1d AND '_'$_1d AND RECNO()=i
REPLACE _1dxx WITH '_1DXX' FOR '_'$k_1x AND '_'$_1x AND RECNO()=i
REPLACE _1dxx WITH '_1DXX' FOR '_'$k_1t AND '_'$_1t AND RECNO()=i
FOR NOT '_'$_1dxx AND ('_'$k_1d OR '_'$k_1x OR '_'$k_1t) AND RECNO()=i
ENDFOR
代码应怎样写才能提高运行速度?
最后一行代码有改动

[此贴子已经被作者于2020-9-12 21:17编辑过]

#4
吹水佬2020-09-12 22:31
是不是这样:
只有本站会员才能查看附件,请 登录

程序代码:
USE b2 IN 0 ALIAS t1
USE b2 IN 0 ALIAS t2 AGAIN
SELECT t1
SET RELATION TO RECNO()+1 INTO "t2"
REPLACE ALL t2._1dxx  WITH IIF("_"$t1._1d AND "_"$t2._1d OR "_"$t1._1x AND "_"$t2._1x OR "_"$t1._1t AND "_"$t2._1t, "_1DXX", "");
            t2._1dxxf WITH IIF(EMPTY(t2._1dxx), "_1DXXF", "")
SELECT * FROM t1
#5
吹水佬2020-09-13 09:40
从提供的数据看,优化表结构可以提高效率。
如:
只有本站会员才能查看附件,请 登录

程序代码:
**转换结构格式
SELECT jnh, .F. _1dxx, ICASE(!EMPTY(_1d),1,!EMPTY(_1x),2,!EMPTY(_1t),3,0) _1dxt;
    FROM b2 INTO CURSOR t1 READWRITE
SELECT _1dxt FROM t1 INTO CURSOR t2
SELECT t2
SET RELATION TO RECNO()+1 INTO "t1"
REPLACE ALL t1._1dxx  WITH t2._1dxt>0 AND t1._1dxt==t2._1dxt
SELECT jnh,;
       IIF(_1dxx,"_1DXX",IIF(_1dxt>0,"_1DXXF","      ")) _1dxx,;
       ICASE(_1dxt==1,"_1D",_1dxt==2,"_1X",_1dxt==3,"_1T","   ") _1dxt FROM t1
** 原结构格式显示
SELECT jnh,;
       IIF(!_1dxx AND _1dxt>0,"_1DXXF","      ") _1dxxf,;
       IIF(_1dxx,"_1DXX","     ") _1dxx,;
       IIF(_1dxt==1,"_1D","   ") _1d,;
       IIF(_1dxt==2,"_1X","   ") _1x,;
       IIF(_1dxt==3,"_1T","   ") _1t FROM t1
RETURN


[此贴子已经被作者于2020-9-13 09:43编辑过]

#6
sdta2020-09-13 10:59
以下是引用fdqzy在2020-9-12 20:57:38的发言:

例如下表

对_1d,_1x,_1t上下记录统计,上下记录相同字段连续,则_1dxx, 否则_1dxxf

FOR i=2 TO RECCOUNT()
GO i
SKIP -1
k_1d=_1d
k_1x=_1x
k_1t=_1t
GO i
REPLACE _1dxx WITH '_1DXX' FOR '_'$k_1d AND '_'$_1d AND RECNO()=i
REPLACE _1dxx WITH '_1DXX' FOR '_'$k_1x AND '_'$_1x AND RECNO()=i
REPLACE _1dxx WITH '_1DXX' FOR '_'$k_1t AND '_'$_1t AND RECNO()=i
FOR NOT '_'$_1dxx AND ('_'$k_1d OR '_'$k_1x OR '_'$k_1t) AND RECNO()=i
ENDFOR
代码应怎样写才能提高运行速度?
最后一行代码有改动

例如能解决问题吗
#7
fdqzy2020-09-13 12:07
回复 4楼 吹水佬
老师,是这样,谢谢!
    十多年前学了点VFP6.0,对SQL、数组等都未接触过,统计程序很原始,且丢了近十年,现因统计需要,又开始接触它。
    自在此论坛以来,在老师们的帮助指导下,学到了许多知识,基本全新的,方法、知识、思维方式都是全新的,受益非浅。为了优化我的传统代码,特别是运行速度,能让几万条记录在较短的时间统计出结果,我在此陆续将需要解决的主要问题发上来,请老师们指点帮助,希望能一直关注此帖后续,谢谢!
#8
fdqzy2020-09-13 12:27
以下是引用吹水佬在2020-9-13 09:40:01的发言:

从提供的数据看,优化表结构可以提高效率。
如:

**转换结构格式
SELECT jnh, .F. _1dxx, ICASE(!EMPTY(_1d),1,!EMPTY(_1x),2,!EMPTY(_1t),3,0) _1dxt;
    FROM b2 INTO CURSOR t1 READWRITE
SELECT _1dxt FROM t1 INTO CURSOR t2
SELECT t2
SET RELATION TO RECNO()+1 INTO "t1"
REPLACE ALL t1._1dxx  WITH t2._1dxt>0 AND t1._1dxt==t2._1dxt
SELECT jnh,;
       IIF(_1dxx,"_1DXX",IIF(_1dxt>0,"_1DXXF","      ")) _1dxx,;
       ICASE(_1dxt==1,"_1D",_1dxt==2,"_1X",_1dxt==3,"_1T","   ") _1dxt FROM t1
** 原结构格式显示
SELECT jnh,;
       IIF(!_1dxx AND _1dxt>0,"_1DXXF","      ") _1dxxf,;
       IIF(_1dxx,"_1DXX","     ") _1dxx,;
       IIF(_1dxt==1,"_1D","   ") _1d,;
       IIF(_1dxt==2,"_1X","   ") _1x,;
       IIF(_1dxt==3,"_1T","   ") _1t FROM t1
RETURN

有劳了,我在原始表中运行一下!
#9
fdqzy2020-09-13 15:03
回复 6楼 sdta
老师:
SELECT t2
SET RELATION TO RECNO()+1 INTO "t1"
上面语句是t2的上1行与t1的当前行关联?
REPLACE ALL t1._1dxx  WITH t2._1dxt>0 AND t1._1dxt==t2._1dxt
t2的上1行与t1的当前行的_1dxt相等时,为.T.?
#10
fdqzy2020-09-13 15:05
回复 5楼 吹水佬
老师:
SELECT t2
SET RELATION TO RECNO()+1 INTO "t1"
上面语句是t2的上1行与t1的当前行关联?
REPLACE ALL t1._1dxx  WITH t2._1dxt>0 AND t1._1dxt==t2._1dxt
t2的上1行与t1的当前行的_1dxt相等时,为.T.?
#11
fdqzy2020-09-13 15:07
以下是引用sdta在2020-9-13 10:59:30的发言:


例如能解决问题吗

最后一行代码应是:
 
REPLACE _1dxxf WITH '_1DXXF' FOR NOT '_'$_1dxx AND ('_'$k_1d OR '_'$k_1x OR '_'$k_1t) AND RECNO()=i
#12
sdta2020-09-13 15:12
以下是引用fdqzy在2020-9-13 15:03:35的发言:

老师:
SELECT t2
SET RELATION TO RECNO()+1 INTO "t1"
上面语句是t2的上1行与t1的当前行关联?
REPLACE ALL t1._1dxx  WITH t2._1dxt>0 AND t1._1dxt==t2._1dxt
t2的上1行与t1的当前行的_1dxt相等时,为.T.?

没这样用过

[此贴子已经被作者于2020-9-13 15:13编辑过]

#13
吹水佬2020-09-13 16:20
以下是引用fdqzy在2020-9-13 15:05:19的发言:

老师:
SELECT t2
SET RELATION TO RECNO()+1 INTO "t1"
上面语句是t2的上1行与t1的当前行关联?
REPLACE ALL t1._1dxx  WITH t2._1dxt>0 AND t1._1dxt==t2._1dxt
t2的上1行与t1的当前行的_1dxt相等时,为.T.?

RECNO()是t2的当前记录号
RECNO()+1就是说:
t2的当前行与t1相对应行的下一行,t2行1时t1行2, t2行2时t1行3, ......
#14
吹水佬2020-09-13 16:24
用 SELECT SQL 语句,测试一下:
SELECT a.jnh, (b._1dxt>0 AND a._1dxt==b._1dxt) _1dxx, a._1dxt;
    FROM t1 a, t1 b;
    WHERE a.jnh==(b.jnh+1)
#15
fdqzy2020-09-13 18:14
以下是引用吹水佬在2020-9-13 16:24:29的发言:

用 SELECT SQL 语句,测试一下:
SELECT a.jnh, (b._1dxt>0 AND a._1dxt==b._1dxt) _1dxx, a._1dxt;
    FROM t1 a, t1 b;
    WHERE a.jnh==(b.jnh+1)


REPLACE ALL t1._1dxx  WITH t2._1dxt>0 AND t1._1dxt==t2._1dxt
  
SELECT jnh,;
       IIF(_1dxx,"_1DXX",IIF(_1dxt>0,"_1DXXF","      ")) _1dxx,;
       ICASE(_1dxt==1,"_1D",_1dxt==2,"_1X",_1dxt==3,"_1T","   ") _1dxt FROM t1
结果一样,代码更简捷!

[此贴子已经被作者于2020-9-13 18:55编辑过]

#16
fdqzy2020-09-13 18:26
以上方法代码简捷,运行效率高,我还得一一来学。
按4楼的方法:
表:
只有本站会员才能查看附件,请 登录

程序代码:
CLOSE TABLES all

USE b1 IN 0 ALIAS t1
BLANK FIELDS _1d, _1x,_1t,_2d, _2x,_2t ALL
USE b1 IN 0 ALIAS t2 AGAIN

SELECT t1

SET RELATION TO RECNO()+1 INTO "t2"


REPLACE ALL t2._1d  WITH IIF(t2.a1>t1.a1 ,"_1D", "");
            t2._1x  WITH IIF(t2.a1<t1.a1 ,"_1X", "");
            t2._1t  WITH IIF(t2.a1=t1.a1 ,"_1t", "");
            t2._2d  WITH IIF(t2.a2>t1.a2 ,"_2D", "");
            t2._2x  WITH IIF(t2.a2<t1.a2 ,"_2X", "");
            t2._2t  WITH IIF(t2.a2=t1.a2 ,"_2t", "")
           
SET RELATION TO
SELECT * FROM t1
BROWSE

没有问题,且运行比以前快多了
注:
"_1D"-下1行比上1行对应值大
"_1X"-下1行比上1行对应值小
"_1T"-下1行比上1行对应值相同



下面用变量就出问题
程序代码:
CLOSE TABLES all
USE b1 IN 0 ALIAS t1
BLANK FIELDS _1d, _1x,_1t,_2d, _2x,_2t ALL
USE b1 IN 0 ALIAS t2 AGAIN

SELECT t1

SET RELATION TO RECNO()+1 INTO "t2"

p1=ALLTRIM("t1.")+ALLTRIM('a')+ALLTRIM('1')
p11=&p1
k1=ALLTRIM("t2.")+ALLTRIM('a')+ALLTRIM('1')
k11=&k1
p2=ALLTRIM("t1.")+ALLTRIM('a')+ALLTRIM('2')
p22=&p2
k2=ALLTRIM("t2.")+ALLTRIM('a')+ALLTRIM('2')
k22=&k2
REPLACE ALL t2._1d  WITH IIF(k11>p11 ,"_1D", "");
            t2._1x  WITH IIF(k11<p11 ,"_1X", "");
            t2._1t  WITH IIF(k11=p11 ,"_1t", "");
            t2._2d  WITH IIF(k22>p22 ,"_2D", "");
            t2._2x  WITH IIF(k22<p22 ,"_2X", "");
            t2._2t  WITH IIF(k22=p22 ,"_2t", "")
           
SET RELATION TO
SELECT * FROM t1
BROWSE

问题在哪?

[此贴子已经被作者于2020-9-13 18:45编辑过]

#17
吹水佬2020-09-13 19:54
回复 15楼 fdqzy
数据记录多时可测试一下 SET RELATION TO 与 SELECT SQL 的速度,有时表面看语句简单并不就高效。
#18
吹水佬2020-09-13 19:57
回复 16楼 fdqzy
k11、p11等变量只获取了一条记录的数据
REPLACE ALL 是处理所有记录数据
#19
吹水佬2020-09-13 19:59
p1=ALLTRIM("t1.")+ALLTRIM('a')+ALLTRIM('1')
p11=&p1
相当于直接写 p11 = t1.a1
#20
吹水佬2020-09-13 20:09
以下是引用fdqzy在2020-9-13 18:26:48的发言:

以上方法代码简捷,运行效率高,我还得一一来学。
按4楼的方法:
表:
CLOSE TABLES all

USE b1 IN 0 ALIAS t1
BLANK FIELDS _1d, _1x,_1t,_2d, _2x,_2t ALL
USE b1 IN 0 ALIAS t2 AGAIN

BLANK FIELDS _1d, _1x,_1t,_2d, _2x,_2t ALL
这句可以不要,因下面的 REPLACE ALL 处理了
#21
fdqzy2020-09-13 20:57
以下是引用吹水佬在2020-9-13 19:57:05的发言:

k11、p11等变量只获取了一条记录的数据
REPLACE ALL 是处理所有记录数据

因数据结构需要,要多次用到列变量,应如何处理?再嵌套循环吗?
#22
吹水佬2020-09-13 22:19
以下是引用fdqzy在2020-9-13 20:57:23的发言:


因数据结构需要,要多次用到列变量,应如何处理?再嵌套循环吗?

可用EVALUATE()来解释运行动态运算表达式,能不用宏替换就不用。
程序代码:
USE b1 IN 0 ALIAS t1
USE b1 IN 0 ALIAS t2 AGAIN
SELECT t1
SET RELATION TO RECNO()+1 INTO "t2"
p1=ALLTRIM("t1.")+ALLTRIM('a')+ALLTRIM('1')    && 按实际定义动态运算表达式
k1=ALLTRIM("t2.")+ALLTRIM('a')+ALLTRIM('1')
p2=ALLTRIM("t1.")+ALLTRIM('a')+ALLTRIM('2')
k2=ALLTRIM("t2.")+ALLTRIM('a')+ALLTRIM('2')
REPLACE ALL t2._1d WITH IIF(EVALUATE(k1+">"+p1), "_1D", "");
            t2._1x WITH IIF(EVALUATE(k1+"<"+p1), "_1X", "");
            t2._1t WITH IIF(EVALUATE(k1+"="+p1), "_1T", "");
            t2._2d WITH IIF(EVALUATE(k2+">"+p2), "_2D", "");
            t2._2x WITH IIF(EVALUATE(k2+"<"+p2), "_2X", "");
            t2._2t WITH IIF(EVALUATE(k2+"="+p2), "_2T", "")
SET RELATION TO
SELECT * FROM t1
#23
fdqzy2020-09-14 04:47
以下是引用吹水佬在2020-9-13 22:19:25的发言:


可用EVALUATE()来解释运行动态运算表达式,能不用宏替换就不用。
USE b1 IN 0 ALIAS t1
USE b1 IN 0 ALIAS t2 AGAIN
SELECT t1
SET RELATION TO RECNO()+1 INTO "t2"
p1=ALLTRIM("t1.")+ALLTRIM('a')+ALLTRIM('1')    && 按实际定义动态运算表达式
k1=ALLTRIM("t2.")+ALLTRIM('a')+ALLTRIM('1')
p2=ALLTRIM("t1.")+ALLTRIM('a')+ALLTRIM('2')
k2=ALLTRIM("t2.")+ALLTRIM('a')+ALLTRIM('2')
REPLACE ALL t2._1d WITH IIF(EVALUATE(k1+">"+p1), "_1D", "");
            t2._1x WITH IIF(EVALUATE(k1+"<"+p1), "_1X", "");
            t2._1t WITH IIF(EVALUATE(k1+"="+p1), "_1T", "");
            t2._2d WITH IIF(EVALUATE(k2+">"+p2), "_2D", "");
            t2._2x WITH IIF(EVALUATE(k2+"<"+p2), "_2X", "");
            t2._2t WITH IIF(EVALUATE(k2+"="+p2), "_2T", "")
SET RELATION TO
SELECT * FROM t1

漂亮,又学一招!
#24
吹水佬2020-09-14 11:28
回复 23楼 fdqzy
用 EXECSCRIPT() 解释执行动态语句效率相对会更好些
如:
p1=ALLTRIM("t1.")+ALLTRIM('a')+ALLTRIM('1')
k1=ALLTRIM("t2.")+ALLTRIM('a')+ALLTRIM('1')
p2=ALLTRIM("t1.")+ALLTRIM('a')+ALLTRIM('2')
k2=ALLTRIM("t2.")+ALLTRIM('a')+ALLTRIM('2')
cmd = "REPLACE ALL "+;
      "t2._1d WITH IIF(" + k1 + ">" + p1 + ", '_1D', ''),"+;
      "t2._1x WITH IIF(" + k1 + "<" + p1 + ", '_1X', ''),"+;
      "t2._1t WITH IIF(" + k1 + "=" + p1 + ", '_1T', ''),"+;
      "t2._2d WITH IIF(" + k2 + ">" + p2 + ", '_2D', ''),"+;
      "t2._2x WITH IIF(" + k2 + "<" + p2 + ", '_2X', ''),"+;
      "t2._2t WITH IIF(" + k2 + "=" + p2 + ", '_2T', '')"   
EXECSCRIPT(cmd)
#25
fdqzy2020-09-14 13:57
以下是引用吹水佬在2020-9-14 11:28:17的发言:

用 EXECSCRIPT() 解释执行动态语句效率相对会更好些
如:
p1=ALLTRIM("t1.")+ALLTRIM('a')+ALLTRIM('1')
k1=ALLTRIM("t2.")+ALLTRIM('a')+ALLTRIM('1')
p2=ALLTRIM("t1.")+ALLTRIM('a')+ALLTRIM('2')
k2=ALLTRIM("t2.")+ALLTRIM('a')+ALLTRIM('2')
cmd = "REPLACE ALL "+;
      "t2._1d WITH IIF(" + k1 + ">" + p1 + ", '_1D', ''),"+;
      "t2._1x WITH IIF(" + k1 + "<" + p1 + ", '_1X', ''),"+;
      "t2._1t WITH IIF(" + k1 + "=" + p1 + ", '_1T', ''),"+;
      "t2._2d WITH IIF(" + k2 + ">" + p2 + ", '_2D', ''),"+;
      "t2._2x WITH IIF(" + k2 + "<" + p2 + ", '_2X', ''),"+;
      "t2._2t WITH IIF(" + k2 + "=" + p2 + ", '_2T', '')"   
EXECSCRIPT(cmd)

好,比原来快很多!
#26
fdqzy2020-09-14 15:51
与固定行数据比较
只有本站会员才能查看附件,请 登录

程序代码:
CLOSE TABLES all
USE b4
GO 1  &&固定被比较的行
k1=_1d
k2=_1x
k3=_1t
FOR i=2 TO RECCOUNT()  &&以下数据与第1行数据比较
GO i
REPLACE _1dxx WITH '_1DXX' FOR '_'$k1 AND '_'$_1d AND RECNO()=i  &&与第1行同列值相同
REPLACE _1dxx WITH '_1DXX' FOR '_'$k2 AND '_'$_1x AND RECNO()=i
REPLACE _1dxx WITH '_1DXX' FOR '_'$k3 AND '_'$_1t AND RECNO()=i
REPLACE _1dxxf WITH '_1DXXF' FOR NOT '_'$_1dxx AND ('_'$k1 OR '_'$k2 OR '_'$k3) AND RECNO()=i
endfor

运行很慢,麻烦优化一下,谢谢!

[此贴子已经被作者于2020-9-14 15:57编辑过]

#27
吹水佬2020-09-14 17:09
回复 26楼 fdqzy
尽量不用或少用循环,遍历表用SCAN效率高些
试试这样:
USE b4
GO 1  &&固定被比较的行
k1 = '_'$_1d
k2 = '_'$_1x
k3 = '_'$_1t
kk = k1 OR k2 OR k3
GO 2
REPLACE REST _1dxx WITH IIF((k1 AND '_'$_1d) OR (k2 AND '_'$_1x) OR (k3 AND '_'$_1t), '_1DXX', ''),;
             _1dxxf WITH IIF((NOT '_'$_1dxx) AND kk, '_1DXXF', '')
#28
fdqzy2020-09-14 19:41
以下是引用吹水佬在2020-9-14 17:09:49的发言:

尽量不用或少用循环,遍历表用SCAN效率高些
试试这样:
USE b4
GO 1  &&固定被比较的行
k1 = '_'$_1d
k2 = '_'$_1x
k3 = '_'$_1t
kk = k1 OR k2 OR k3
GO 2
REPLACE REST _1dxx WITH IIF((k1 AND '_'$_1d) OR (k2 AND '_'$_1x) OR (k3 AND '_'$_1t), '_1DXX', ''),;
             _1dxxf WITH IIF((NOT '_'$_1dxx) AND kk, '_1DXXF', '')

妙!
由于所学知识太少,以前基本都用循环,所以效率低,在老师的指导下,改变传统编程方法。

[此贴子已经被作者于2020-9-14 19:53编辑过]

#29
fdqzy2020-09-14 19:52
---对筛选数据统计
只有本站会员才能查看附件,请 登录

程序代码:
CLOSE TABLES all
USE b1 IN 0 ALIAS t1
BLANK FIELDS s1_3,s4 all
For i=10 To RECCOUNT()
GO i
p1=ALLTRIM('a')+ALLTRIM('1')
p11=&p1                 &&确定要统计个数的对象
        qs=jnh
        Select * From t1 Where jnh>qs-10 And jnh<=qs Into Cursor ls  &&筛选10行数据
        Count For a1=p11 Or a2=p11  To tj &&对筛选数据统计
            
        Use
        Select t1
        GO i
REPLACE s1_3 with 'S1_3' for tj>0 AND tj<=3 AND RECNO()=i
REPLACE s4 with 'S4' for tj>3 AND RECNO()=i

ENDFOR
brow

如何改进?谢谢!
#30
fdqzy2020-09-14 19:57
以下是引用吹水佬在2020-9-14 17:09:49的发言:

kk = k1 OR k2 OR k3

这样设变量,没见过!
#31
吹水佬2020-09-14 22:13
回复 30楼 fdqzy
逻辑运算
#32
吹水佬2020-09-14 22:19
以下是引用fdqzy在2020-9-14 19:52:51的发言:

---对筛选数据统计

CLOSE TABLES all
USE b1 IN 0 ALIAS t1
BLANK FIELDS s1_3,s4 all
For i=10 To RECCOUNT()
GO i
p1=ALLTRIM('a')+ALLTRIM('1')
p11=&p1                 &&确定要统计个数的对象
        qs=jnh
        Select * From t1 Where jnh>qs-10 And jnh<=qs Into Cursor ls  &&筛选10行数据
        Count For a1=p11 Or a2=p11  To tj &&对筛选数据统计
            
        Use
        Select t1
        GO i
REPLACE s1_3 with 'S1_3' for tj>0 AND tj<=3 AND RECNO()=i
REPLACE s4 with 'S4' for tj>3 AND RECNO()=i

ENDFOR
brow
如何改进?谢谢!

REPLACE ...... for ...,带FOR子句,如果不指定记录范围相当于 REPLACE ALL
精简部份:
程序代码:
GO 10
SCAN REST
    p11 = a1
    qs = jnh
    SELECT COUNT(*) FROM t1 WHERE BETWEEN(jnh,qs-9,qs) AND (a1=p11 OR a2=p11) INTO ARRAY tj
    REPLACE s1_3 WITH IIF(tj>0 AND tj<=3, 'S1_3', ''), s4 WITH IIF(tj>3, 'S4', '')
ENDSCAN

#33
fdqzy2020-09-14 22:45
以下是引用吹水佬在2020-9-14 22:19:18的发言:


REPLACE ...... for ...,带FOR子句,如果不指定记录范围相当于 REPLACE ALL
精简部份:
GO 10
SCAN REST
    p11 = a1
    qs = jnh
    SELECT COUNT(*) FROM t1 WHERE BETWEEN(jnh,qs-9,qs) AND (a1=p11 OR a2=p11) INTO ARRAY tj
    REPLACE s1_3 WITH IIF(tj>0 AND tj<=3, 'S1_3', ''), s4 WITH IIF(tj>3, 'S4', '')
ENDSCAN

谢谢!明天继续请教。
#34
吹水佬2020-09-15 16:09
回复 33楼 fdqzy
试试这样能快多少
程序代码:

USE b1
BLANK FIELDS s1_3,s4 all
GO TOP
DIMENSION a12[10,2]
COPY TO ARRAY a12 FIELDS a1,a2 NEXT 9
SKIP
SCAN REST
    p11 = a1
    a12[10,1] = a1
    a12[10,2] = a2
    tj = 1
    FOR i=1 TO 9
        IF a12[i,1]=p11 OR a12[i,2]=p11
            tj = tj + 1
        ENDIF
    ENDFOR
    REPLACE s1_3 WITH IIF(tj<4, 'S1_3', ''), s4 WITH IIF(tj>3, 'S4', '')
    ADEL(a12,1)
ENDSCAN
SELECT * FROM b1



[此贴子已经被作者于2020-9-15 16:22编辑过]

#35
fdqzy2020-09-15 16:37
以下是引用吹水佬在2020-9-15 16:09:51的发言:

试试这样能快多少

USE b1
BLANK FIELDS s1_3,s4 all
GO TOP
DIMENSION a12[10,2]
COPY TO ARRAY a12 FIELDS a1,a2 NEXT 9
SKIP
SCAN REST
    p11 = a1
    a12[10,1] = a1
    a12[10,2] = a2
    tj = 1
    FOR i=1 TO 9
        IF a12[i,1]=p11 OR a12[i,2]=p11
            tj = tj + 1
        ENDIF
    ENDFOR
    REPLACE s1_3 WITH IIF(tj<4, 'S1_3', ''), s4 WITH IIF(tj>3, 'S4', '')
    ADEL(a12,1)
ENDSCAN
SELECT * FROM b1

绝了!
我在前面的代码中测试:
20000条记录耗时1分多钟;
96000多条记录,耗时42分钟
用此代码,耗时1秒多点。
我还正为此事发愁,没想到解决得如此好!
测试数据
只有本站会员才能查看附件,请 登录
#36
fdqzy2020-09-15 16:52
回复 35楼 fdqzy
我还没看懂此代码与前面代码的联系,能否解释一下!
另外,统计范围改成固定前9行,加上第10行及以后的1行(共10行)进行统计,
即前面代码的
SELECT COUNT(*) FROM t1 WHERE BETWEEN(jnh,qs-9,qs) AND (a1=p11 OR a2=p11) INTO ARRAY tj
改为
SELECT COUNT(*) FROM t1 WHERE ((jnh>1 And jnh<=9) OR jnh=qs) AND (a1=p11 OR a2=p11) INTO ARRAY tj



 
#37
fdqzy2020-09-15 17:06
以下是引用吹水佬在2020-9-15 16:09:51的发言:

试试这样能快多少

USE b1
BLANK FIELDS s1_3,s4 all
GO TOP
DIMENSION a12[10,2]
COPY TO ARRAY a12 FIELDS a1,a2 NEXT 9
SKIP
SCAN REST
    p11 = a1
    a12[10,1] = a1
    a12[10,2] = a2
    tj = 1
    FOR i=1 TO 9
        IF a12[i,1]=p11 OR a12[i,2]=p11
            tj = tj + 1
        ENDIF
    ENDFOR
    REPLACE s1_3 WITH IIF(tj<4, 'S1_3', ''), s4 WITH IIF(tj>3, 'S4', '')
    ADEL(a12,1)
ENDSCAN
SELECT * FROM b1

前面代码
SELECT COUNT(*) FROM t1 WHERE BETWEEN(jnh,qs-9,qs) AND (a1=p11 OR a2=p11) INTO ARRAY tj
中的BETWEEN(jnh,qs-9,qs)在哪反映?
#38
吹水佬2020-09-15 17:40
以下是引用fdqzy在2020-9-15 16:52:40的发言:

我还没看懂此代码与前面代码的联系,能否解释一下!

 

理解是:按 1..10、 2..11、 3..12、...每次10行进行统计。
用数组来存放统计的数据,每次先获取第10行数据,统计完删除第1行数据,删除第1行后后面的数据向前移。
#39
吹水佬2020-09-15 18:08
以下是引用fdqzy在2020-9-15 16:52:40的发言:

另外,统计范围改成固定前9行,加上第10行及以后的1行(共10行)进行统计,
即前面代码的

固定前9行:
GO TOP
DIMENSION a12[10,2]
COPY TO ARRAY a12 FIELDS a1,a2 NEXT 9     &&这句是取最前9行
第10行及以后的1行放到 a12[10,1]、a12[10,2]



#40
吹水佬2020-09-15 20:24
以下是引用fdqzy在2020-9-15 17:06:09的发言:


前面代码
SELECT COUNT(*) FROM t1 WHERE BETWEEN(jnh,qs-9,qs) AND (a1=p11 OR a2=p11) INTO ARRAY tj
中的BETWEEN(jnh,qs-9,qs)在哪反映?

BETWEEN(jnh,qs-9,qs)就是取连续的10行进行统计
相当于:
    tj = 1  && 因第10行的数据用作条件判断参数,肯定成立,tj最小为1
    FOR i=1 TO 9  && 统计1--9行
        IF a12[i,1]=p11 OR a12[i,2]=p11
            tj = tj + 1
        ENDIF
    ENDFOR

这样做就不用每次COUNT统计时要遍历表,从而大大提高效率。
#41
fdqzy2020-09-15 20:50
老师:
这种代码没学过,必须读懂,才能依样画葫芦仿照运用,不枉老师的一片心。
我的理解如下(有的是错误的,请指正):
程序代码:
USE b1
BLANK FIELDS s1_3,s4 all
GO TOP
DIMENSION a12[10,2]  &&定义二维数据变量,10-要统计的10行,2-列数(如果是3列就是a12[10,3]
COPY TO ARRAY a12 FIELDS a1,a2 NEXT 9  &&复制当前和下9条记录(这个理解可能是错误的)

SKIP  && 指针下移(是如何移到第10行的 ?,如果前面“GO TOP”改为"GO 2",这里就是下移到第11行?)
SCAN REST &&从第10行开始扫描
    p11 = a1
    a12[10,1] = a1
    a12[10,2] = a2
    tj = 1  &&为什么初始值斌“1”?
    FOR i=1 TO 9 &&从1行到9行统计
        IF a12[i,1]=p11 OR a12[i,2]=p11
            tj = tj + 1  &&如果 a12[i,1]、a12[i,2]都等于p11,这个成立否?
        ENDIF
    ENDFOR
    REPLACE s1_3 WITH IIF(tj<4, 'S1_3', ''), s4 WITH IIF(tj>3, 'S4', '')
    ADEL(a12,1) &&删除数组第1行元素
ENDSCAN
SELECT * FROM b1

这是按1-10,2-11,3-12....进行统计的
如果要固定前9行,再与10行及以后每1行组成10行统计(即前9行+第10行,前9行+第11行,前9行+第12行.....)
应如何修改代码?

麻烦了!

[此贴子已经被作者于2020-9-15 20:53编辑过]

#42
吹水佬2020-09-15 23:31
回复 41楼 fdqzy
理解没什么大问题
固定前9行和统计过程在39、40楼有提到
IF语句的判断表达式符合实际要求就OK
#43
吹水佬2020-09-15 23:55
以下是引用fdqzy在2020-9-15 20:50:11的发言:

如果要固定前9行,再与10行及以后每1行组成10行统计(即前9行+第10行,前9行+第11行,前9行+第12行.....)
应如何修改代码?
麻烦了!

改小小,每次统计后不删除数组的第一行就可以固定前9行,每次取第10的数据就可以。
程序代码:
USE b1
BLANK FIELDS s1_3,s4 all
GO TOP
DIMENSION a12[10,2]  &&定义二维数据变量,10-要统计的10行,2-列数(如果是3列就是a12[10,3]
COPY TO ARRAY a12 FIELDS a1,a2 NEXT 9  &&复制从当前行起计共9条记录(此时是最上面的9条记录)
SKIP  && 指针下移(执行COPY后记录指针指向第9行,执行SKIP后移到第10行,如果前面“GO TOP”改为"GO 2",这里就是下移到第11行
SCAN REST &&从第10行开始扫描
    p11 = a1
    a12[10,1] = a1
    a12[10,2] = a2
    tj = 1  &&为什么初始值斌“1”? 因第10行(a12[10,1]=p11 OR a12[10,2]=p11)肯定为真,tj最小为1
    FOR i=1 TO 9 &&从1行到9行统计
        IF a12[i,1]=p11 OR a12[i,2]=p11
            tj = tj + 1  &&如果 a12[i,1]、a12[i,2]都等于p11,这个成立否? 肯定成立,因是OR运算,两者有一个成立就为真
        ENDIF
    ENDFOR
    REPLACE s1_3 WITH IIF(tj<4, 'S1_3', ''), s4 WITH IIF(tj>3, 'S4', '')
    **ADEL(a12,1) &&删除数组第1行元素,要固定前9行的就不用删除
ENDSCAN
SELECT * FROM b1
#44
csyx2020-09-16 04:37
先学好走,再考虑跑
3楼代码的主要问题,是对 replace 命令的作用范围不够了解
正如吹版在32楼指出的,带 for 子句的 replace 作用范围是 all,这在 vfp 的帮助里有明确的说明
因此,如果有 N 条记录,你的 for循环 + replace 要遍历整个表 N * N 次
(假设表没有任何索引,或者有但却无法被 vfp 的 rushmore 利用)

所以,你只要给 replace 加上范围子句,就可以简单的让运行时间得到根本性改变
例如第一条:REPLACE Next 1 _1dxx WITH '_1DXX' FOR '_'$k_1d AND '_'$_1d      && AND RECNO()=i

[此贴子已经被作者于2020-9-16 04:40编辑过]

#45
fdqzy2020-09-16 08:56
以下是引用csyx在2020-9-16 04:37:42的发言:

先学好走,再考虑跑
3楼代码的主要问题,是对 replace 命令的作用范围不够了解
正如吹版在32楼指出的,带 for 子句的 replace 作用范围是 all,这在 vfp 的帮助里有明确的说明
因此,如果有 N 条记录,你的 for循环 + replace 要遍历整个表 N * N 次
(假设表没有任何索引,或者有但却无法被 vfp 的 rushmore 利用)

所以,你只要给 replace 加上范围子句,就可以简单的让运行时间得到根本性改变
例如第一条:REPLACE Next 1 _1dxx WITH '_1DXX' FOR '_'$k_1d AND '_'$_1d      && AND RECNO()=i

说得对,学识太浅,在解决实际问题的同时去学习。
#46
fdqzy2020-09-16 14:34
再请教关于行统计的问题:
我的常规处理办法是
程序代码:
create cursor b1 (c1 N(3),c2 N(3),m c(3))
insert into b1 values (70,54,"")
insert into b1 values (58,54,"")
insert into b1 values (49,86,"")
insert into b1 values (66,86,"")
insert into b1 values (75,96,"")

FOR i=1 TO RECCOUNT()
GO i
kk=''
IF c1>=60
kk=kk+'1'
ENDIF
IF c1<60
kk=kk+'0'
ENDIF
IF c2>=60
kk=kk+'1'
ENDIF
IF c2<60
kk=kk+'0'
ENDIF
GO i
REPLACE m WITH ALLTRIM(kk)
endfor


统计:
程序代码:
create cursor b1 (m1 c(2),m2 c(2),m3 c(2),m4 c(2),m5 c(2),p1 c(3),p2 c(3),p3 c(3))
insert into b1 values ("M1","","M3","M4","","","","")
insert into b1 values ("M1","","","M4","","","","")
insert into b1 values ("","M2","M3","M4","M5","","","")
insert into b1 values ("","","","M4","","","","")
insert into b1 values ("","","M3","M4","M5","","","")

FOR i=1 TO RECCOUNT()
GO i
kk=0
IF 'M'$m1
kk=kk+1
ENDIF
IF 'M'$m2
kk=kk+1
ENDIF
IF 'M'$m3
kk=kk+1
ENDIF
IF 'M'$m4
kk=kk+1
ENDIF
IF 'M'$m5
kk=kk+1
ENDIF
GO i
REPLACE p1 WITH 'P1' FOR kk=1 AND RECNO()=i
REPLACE p2 WITH 'P2' FOR kk=2 AND RECNO()=i
REPLACE p3 WITH 'P3' FOR kk>2 AND RECNO()=i

endfor

求简捷的处理方法!

[此贴子已经被作者于2020-9-16 14:36编辑过]

#47
sdta2020-09-16 15:09
create cursor b1 (m1 c(2),m2 c(2),m3 c(2),m4 c(2),m5 c(2),p1 c(3),p2 c(3),p3 c(3))
insert into b1 values ("M1","","M3","M4","","","","")
insert into b1 values ("M1","","","M4","","","","")
insert into b1 values ("","M2","M3","M4","M5","","","")
insert into b1 values ("","","","M4","","","","")
insert into b1 values ("","","M3","M4","M5","","","")
SCAN
    n1 = OCCURS("M", m1 + m2 + m3 + m4 + m5)
    n1 = IIF(n1 > 3, 3, n1)
    REPLACE ("P" + TRANSFORM(n1)) WITH "P" + TRANSFORM(n1)
ENDSCAN
BROWSE
#48
sdta2020-09-16 15:15
create cursor b1 (c1 N(3),c2 N(3),m c(3))
insert into b1 values (70,54,"")
insert into b1 values (58,54,"")
insert into b1 values (49,86,"")
insert into b1 values (66,86,"")
insert into b1 values (75,96,"")
SCAN
    REPLACE m WITH IIF(c1 >= 60, "1", "0") + IIF(c2 >= 60, "1", "0")
ENDSCAN
BROWSE
#49
sdta2020-09-16 15:18
我一直坚持先学后用,不是现学现用,原因大家可以自己去想像
#50
sdta2020-09-16 15:45
REPLACE ...... FOR 条件  是对全表进行操作,凡是加了 FOR 的命令,运行速度都将受到影响,也就是运行时间延长了。
我在上面的回复中避免使用 FOR 子句,从而使程序的运行速度加快了。
SCAN ENDSCAN命令对表中的记录逐条进行扫描,扫描结束后,问题也得到了解决。

[此贴子已经被作者于2020-9-16 15:47编辑过]

#51
吹水佬2020-09-16 16:24
以下是引用fdqzy在2020-9-16 14:34:51的发言:

再请教关于行统计的问题:
我的常规处理办法是
create cursor b1 (c1 N(3),c2 N(3),m c(3))
insert into b1 values (70,54,"")
insert into b1 values (58,54,"")
insert into b1 values (49,86,"")
insert into b1 values (66,86,"")
insert into b1 values (75,96,"")

FOR i=1 TO RECCOUNT()
GO i
kk=''
IF c1>=60
kk=kk+'1'
ENDIF
IF c1<60
kk=kk+'0'
ENDIF
IF c2>=60
kk=kk+'1'
ENDIF
IF c2<60
kk=kk+'0'
ENDIF
GO i
REPLACE m WITH ALLTRIM(kk)
endfor

求简捷的处理方法!

一句
REPLACE ALL m WITH IIF(c1<60,"0","1") + IIF(c2<60,"0","1")
12