注册 登录
编程论坛 VFP论坛

请帮忙,寻求快速计算平均分(0分除外)的方法,谢谢!

schtg 发布于 2023-08-13 06:50, 1295 次点击
各位,另起一题,请教可否还有更快一点的算法,希望缩短执行时间
从表中的 yw 字段开始以后的全部字段均要分别计算:一是全体考生的平均分,二是以地市代码dsdm为准的地市平均分,三是以县区代码xqdm为准的县区平均分,四是以学校代码xxdm为准的学校平均分(0分除外),还需要一部分名次,样表格式如下:
只有本站会员才能查看附件,请 登录

数据表:https://down.bccn.net/12536.html
我使用 select avg()计算,需要较长时间才可以完成,希望得到大侠们的帮助,可否寻找到更优的计算方法,谢谢!

[此贴子已经被作者于2023-8-13 07:04编辑过]

24 回复
#2
吹水佬2023-08-13 08:08
给代码看看
#3
schtg2023-08-13 08:19
回复 2楼 吹水佬
这是计算平均分的(排序在前一题中),我自己的代码纯属胡编乱造的,勿笑


[此贴子已经被作者于2023-8-14 05:43编辑过]

#4
吹水佬2023-08-13 15:00
每一个 SELECT ...SQL要扫描一次,加上循环调用就更慢。
试算了一下ywpjf和sxpjf(其他加上去就是),剩下是算名次。
程序代码:

CREATE CURSOR pjf (dsdm n(6),xqdm n(8),xxdm n(10),ckzrs I,;
                   ywpjf n(12,2),ywlkpx n(12,2),ywbspx n(12,2),ywbxpx n(12,2),;
                   sxpjf n(12,2),sxlkpx n(12,2),sxbspx n(12,2),sxbxpx n(12,2);
                   )
                  
SELECT DISTINCT dsdm FROM cj ORDER BY dsdm INTO CURSOR tmp_dsdm                  
SELECT * FROM pjf WHERE .t. INTO CURSOR pjf_dsdm READWRITE
APPEND FROM DBF("tmp_dsdm")
INDEX on dsdm TAG tag_dsdm

SELECT DISTINCT xqdm FROM cj ORDER BY xqdm INTO CURSOR tmp_xqdm
SELECT * FROM pjf WHERE .t. INTO CURSOR pjf_xqdm READWRITE
APPEND FROM DBF("tmp_xqdm")
INDEX on xqdm TAG tag_xqdm

SELECT DISTINCT xxdm FROM cj ORDER BY xxdm INTO CURSOR tmp_xxdm
SELECT * FROM pjf WHERE .t. INTO CURSOR pjf_xxdm READWRITE
APPEND FROM DBF("tmp_xxdm")
INDEX on xxdm TAG tag_xxdm

INSERT INTO pjf (dsdm,ckzrs) VALUES (0,RECCOUNT("cj"))

SELECT cj
SET RELATION TO dsdm INTO "pjf_dsdm", xqdm INTO "pjf_xqdm", xxdm INTO "pjf_xxdm"
REPLACE ALL pjf.ywpjf      WITH pjf.ywpjf      + cj.yw,;
            pjf.sxpjf      WITH pjf.sxpjf      + cj.sx,;
            pjf_dsdm.ckzrs WITH pjf_dsdm.ckzrs + 1,;
            pjf_dsdm.ywpjf WITH pjf_dsdm.ywpjf + cj.yw,;
            pjf_dsdm.sxpjf WITH pjf_dsdm.sxpjf + cj.sx,;
            pjf_xqdm.ckzrs WITH pjf_xqdm.ckzrs + 1,;
            pjf_xqdm.ywpjf WITH pjf_xqdm.ywpjf + cj.yw,;
            pjf_xqdm.sxpjf WITH pjf_xqdm.sxpjf + cj.sx,;
            pjf_xxdm.ckzrs WITH pjf_xxdm.ckzrs + 1,;
            pjf_xxdm.ywpjf WITH pjf_xxdm.ywpjf + cj.yw,;
            pjf_xxdm.sxpjf WITH pjf_xxdm.sxpjf + cj.sx

SELECT pjf
APPEND FROM DBF("pjf_dsdm")
APPEND FROM DBF("pjf_xqdm")
APPEND FROM DBF("pjf_xxdm")
REPLACE ALL ywpjf WITH ywpjf/ckzrs,;
            sxpjf WITH sxpjf/ckzrs

SELECT * FROM pjf



[此贴子已经被作者于2023-8-13 15:21编辑过]

#5
schtg2023-08-13 16:27
回复 4楼 吹水佬
谢谢!吹版主。
#6
吹水佬2023-08-15 15:37
试了一下,算量还不少,i3的机跑8秒左右
数据未校对
只有本站会员才能查看附件,请 登录

只有本站会员才能查看附件,请 登录

程序代码:

tm=SECONDS()

USE cj
DIMENSION afs[FCOUNT()-5]    && yw及之后的字段名列表
FOR i=6 TO FCOUNT()
     afs[i-5] = FIELD(i)
ENDFOR

    * 创建平均分表
cmd = "CREATE CURSOR pjf (dsdm n(6),xqdm n(8),xxdm n(10),ckzrs I"
FOR i=1 TO ALEN(afs)
    cmd = cmd + "," + afs[i]+"pjf n(12,2)," + afs[i]+"lkpx I," + afs[i]+"bspx I," + afs[i]+"bxpx I"
ENDFOR
cmd = cmd + ")"
EXECSCRIPT(cmd)

    * 从 cj 获取 xxdm 的人数和分数
SELECT DISTINCT dsdm,xqdm,xxdm FROM cj ORDER BY dsdm,xqdm,xxdm INTO CURSOR tmp
SELECT * FROM pjf WHERE .t. INTO CURSOR pjf_xxdm READWRITE
APPEND FROM DBF("tmp")
INDEX on xxdm TAG tag_xxdm
SELECT cj
SET RELATION TO xxdm INTO "pjf_xxdm"
cmd = "REPLACE ALL pjf_xxdm.ckzrs WITH pjf_xxdm.ckzrs+1"
FOR i=1 TO ALEN(afs)
    cmd = cmd + ",pjf_xxdm." + afs[i] + "pjf WITH pjf_xxdm." + afs[i] + "pjf + cj." + afs[i]
ENDFOR
EXECSCRIPT(cmd)
SET RELATION TO

    * 从 pjf_xxdm 获取 xqdm 的人数和分数
SELECT DISTINCT dsdm,xqdm FROM pjf_xxdm ORDER BY dsdm,xqdm INTO CURSOR tmp
SELECT * FROM pjf WHERE .t. INTO CURSOR pjf_xqdm READWRITE
APPEND FROM DBF("tmp")
INDEX on xqdm TAG tag_xqdm
SELECT pjf_xxdm
SET RELATION TO xqdm INTO "pjf_xqdm"
cmd = "REPLACE ALL pjf_xqdm.ckzrs WITH pjf_xqdm.ckzrs + pjf_xxdm.ckzrs"
FOR i=1 TO ALEN(afs)
    cmd = cmd + ",pjf_xqdm." + afs[i] + "pjf WITH pjf_xqdm." + afs[i] + "pjf + pjf_xxdm." + afs[i] + "pjf"
ENDFOR
EXECSCRIPT(cmd)
SET RELATION TO

    * 从 pjf_xqdm 获取 dsdm 的人数和分数
SELECT DISTINCT dsdm FROM pjf_xqdm ORDER BY dsdm INTO CURSOR tmp
SELECT * FROM pjf WHERE .t. INTO CURSOR pjf_dsdm READWRITE
APPEND FROM DBF("tmp")
INDEX on dsdm TAG tag_dsdm
SELECT pjf_xqdm
SET RELATION TO dsdm INTO "pjf_dsdm"
cmd = "REPLACE ALL pjf_dsdm.ckzrs WITH pjf_dsdm.ckzrs + pjf_xqdm.ckzrs"
FOR i=1 TO ALEN(afs)
    cmd = cmd + ",pjf_dsdm." + afs[i] + "pjf WITH pjf_dsdm." + afs[i] + "pjf + pjf_xqdm." + afs[i] + "pjf"
ENDFOR
EXECSCRIPT(cmd)
SET RELATION TO

    * 从 pjf_dsdm 获取总人数和总分数
INSERT INTO pjf (dsdm) VALUES (0)
SELECT pjf_dsdm
cmd = "REPLACE ALL pjf.ckzrs WITH pjf.ckzrs + pjf_dsdm.ckzrs"
FOR i=1 TO ALEN(afs)
    cmd = cmd + ",pjf." + afs[i] + "pjf WITH pjf." + afs[i] + "pjf + pjf_dsdm." + afs[i] + "pjf"
ENDFOR
EXECSCRIPT(cmd)

    * 统计 各类平均分数
tj_pjf("pjf")
tj_pjf("pjf_dsdm")
tj_pjf("pjf_xqdm")
tj_pjf("pjf_xxdm")

    * 统计 联考名次、本市名次、本县名次
tj_mcs("xqdm")
tj_mcs("xxdm")

    * 整合各类表
SELECT pjf
APPEND FROM DBF("pjf_dsdm")
APPEND FROM DBF("pjf_xqdm")
APPEND FROM DBF("pjf_xxdm")

? SECONDS()-tm
SELECT * FROM pjf
CLOSE TABLES ALL
RETURN

    * 统计平均分
FUNCTION tj_pjf(cAlias)
    cmd = ""
    FOR i=1 TO ALEN(afs)
        cmd = cmd + "," + afs[i] + "pjf WITH " + afs[i] + "pjf/ckzrs"
    ENDFOR
    cmd = "REPLACE ALL " + SUBSTR(cmd,2) + " IN " + cAlias
    EXECSCRIPT(cmd)
ENDFUNC

    * 统计 联考名次、本市名次、本县名次
FUNCTION tj_mcs(dmm)
    FOR i=1 TO ALEN(afs)
        tj_mc(dmm, afs[i])
    ENDFOR
ENDFUNC

    * 统计x类x科 联考名次、本市名次、本县名次
FUNCTION tj_mc(dmm, kmm)
        * 联考名次
    cmd = "SELECT " + dmm + "," + kmm + "pjf FROM pjf_" + dmm + " ORDER BY " + kmm + "pjf DESC INTO CURSOR tmp"
    EXECSCRIPT(cmd)
    EXECSCRIPT("SET RELATION TO " + dmm + " INTO pjf_" + dmm)
    m = 1
    n = 1
    fs = 0
    SCAN
        IF EVALUATE(kmm+"pjf") != fs
            fs = EVALUATE(kmm+"pjf")
            n = m
        ENDIF
        REPLACE ("pjf_" + dmm + "." + kmm + "lkpx") WITH n
        m = m + 1
    ENDSCAN
    SET RELATION TO
    USE IN "tmp"
        * 本市名次
    cmd = "SELECT dsdm," + dmm + "," + kmm + "pjf FROM pjf_" + dmm + " ORDER BY dsdm," + kmm + "pjf DESC INTO CURSOR tmp"
    EXECSCRIPT(cmd)
    EXECSCRIPT("SET RELATION TO " + dmm + " INTO pjf_" + dmm)  
    m = 1
    n = 1
    dm = 0
    fs = 0
    SCAN
        IF dm != dsdm
            m = 1
            n = 1
            dm = dsdm
            fs = EVALUATE(kmm+"pjf")
        ENDIF
        IF EVALUATE(kmm+"pjf") != fs
            fs = EVALUATE(kmm+"pjf")
            n = m
        ENDIF
        REPLACE ("pjf_" + dmm + "." + kmm + "bspx") WITH n
        m = m + 1
    ENDSCAN
    SET RELATION TO
    USE IN "tmp"
   
    IF dmm != "xxdm"  
        RETURN
    ENDIF
        * 本县名次
    cmd = "SELECT dsdm,xqdm,xxdm," + kmm + "pjf FROM pjf_xxdm ORDER BY xqdm," + kmm + "pjf DESC INTO CURSOR tmp"
    EXECSCRIPT(cmd)
    SET RELATION TO xxdm INTO pjf_xxdm
    m = 1
    n = 1
    dm = 0
    fs = 0
    SCAN
        IF dm != xqdm
            m = 1
            n = 1
            dm = xqdm
            fs = EVALUATE(kmm+"pjf")
        ENDIF  
        IF EVALUATE(kmm+"pjf") != fs
            fs = EVALUATE(kmm+"pjf")
            n = m
        ENDIF
        REPLACE ("pjf_xxdm." + kmm + "bxpx") WITH n
        m = m + 1
    ENDSCAN
ENDFUNC
#7
schtg2023-08-15 16:26
回复 6楼 吹水佬
吹版主,非常感谢!谢谢你的大力赐教!
我们计算平均分时,一般不将零分计算其中,要把零分人数从总人数中减去。

[此贴子已经被作者于2023-8-16 07:53编辑过]

#8
schtg2023-08-16 11:39
回复 6楼 吹水佬
吹版主,请问如果计算平均分时排除 零分,如何修改为佳?谢谢!
#9
吹水佬2023-08-16 11:49
以下是引用schtg在2023-8-16 11:39:32的发言:

吹版主,请问如果计算平均分时排除 零分,如何修改为佳?谢谢!

开始或最后结果全0的记录可以去掉,其中有一不是0的记录也去不了吧
#10
schtg2023-08-16 13:44
回复 9楼 吹水佬
我们时按照单学科来计算平均分的,计算语文平均分时,语文成绩为0的学生不计入总人数中,即语文分数总和/语文成绩大于0的学生总人数。如果用select avg()表示的话,就是:select avg(yw) as ywpjf from tablename where yw > 0。不知我讲明白了吗
#11
吹水佬2023-08-16 16:07
回复 10楼 schtg
同一分类,0分虽不影响各学科的总分数,但0分的不计人数,各学科的总人数可能不是相同的,那就要分类分科统计总人数了。
能不能优化一下数据结构,分输入数据结构(原始数据结构)、输出数据结构(显示数据结构)
#12
schtg2023-08-16 16:25
回复 11楼 吹水佬
对方提供的数据就是这样的哈,只能分类分科统计啦。
#13
吹水佬2023-08-16 22:57
以下是引用schtg在2023-8-16 16:25:40的发言:

对方提供的数据就是这样的哈,只能分类分科统计啦。


原来的只有一个总人数字段,不符合你的要求。
试改结构分科分类统计人数,未校对
只有本站会员才能查看附件,请 登录

只有本站会员才能查看附件,请 登录

程序代码:

tm=SECONDS()

USE cj
DIMENSION afs[FCOUNT()-5]    && yw及之后的字段名列表
FOR i=6 TO FCOUNT()
     afs[i-5] = FIELD(i)
ENDFOR

    * 创建平均分表
cmd = "CREATE CURSOR pjf (dsdm n(6),xqdm n(8),xxdm n(10)"
FOR i=1 TO ALEN(afs)
    cmd = cmd + "," + afs[i]+"zrs I," + afs[i]+"pjf n(12,2)," + afs[i]+"lkpx I," + afs[i]+"bspx I," + afs[i]+"bxpx I"
ENDFOR
cmd = cmd + ")"
EXECSCRIPT(cmd)

? "从 cj 获取 xxdm 的人数和分数"
SELECT DISTINCT dsdm,xqdm,xxdm FROM cj ORDER BY dsdm,xqdm,xxdm INTO CURSOR tmp
SELECT * FROM pjf WHERE .t. INTO CURSOR pjf_xxdm READWRITE
APPEND FROM DBF("tmp")
INDEX on xxdm TAG tag_xxdm
SELECT cj
SET RELATION TO xxdm INTO "pjf_xxdm"
tj_rsfs("pjf_xxdm")
SET RELATION TO

? "从 pjf_xxdm 获取 xqdm 的人数和分数"
SELECT DISTINCT dsdm,xqdm FROM pjf_xxdm ORDER BY dsdm,xqdm INTO CURSOR tmp
SELECT * FROM pjf WHERE .t. INTO CURSOR pjf_xqdm READWRITE
APPEND FROM DBF("tmp")
INDEX on xqdm TAG tag_xqdm
SELECT pjf_xxdm
SET RELATION TO xqdm INTO "pjf_xqdm"
tj_rsfs("pjf_xqdm")
SET RELATION TO

? "从 pjf_xqdm 获取 dsdm 的人数和分数"
SELECT DISTINCT dsdm FROM pjf_xqdm ORDER BY dsdm INTO CURSOR tmp
SELECT * FROM pjf WHERE .t. INTO CURSOR pjf_dsdm READWRITE
APPEND FROM DBF("tmp")
INDEX on dsdm TAG tag_dsdm
SELECT pjf_xqdm
SET RELATION TO dsdm INTO "pjf_dsdm"
tj_rsfs("pjf_dsdm")
SET RELATION TO

? "从 pjf_dsdm 获取总人数和总分数"
INSERT INTO pjf (dsdm) VALUES (0)
SELECT pjf_dsdm
tj_rsfs("pjf")

? "统计 各类平均分数"
tj_pjf("pjf")
tj_pjf("pjf_dsdm")
tj_pjf("pjf_xqdm")
tj_pjf("pjf_xxdm")

? "统计 联考名次、本市名次、本县名次"
FOR i=1 TO ALEN(afs)
    tj_mc(afs[i], "pjf_xqdm")
    tj_mc(afs[i], "pjf_xxdm")
ENDFOR

    * 整合各类表
SELECT pjf
APPEND FROM DBF("pjf_dsdm")
APPEND FROM DBF("pjf_xqdm")
APPEND FROM DBF("pjf_xxdm")

? SECONDS()-tm
SELECT * FROM pjf
CLOSE TABLES ALL
RETURN

    * 统计人数分数
FUNCTION tj_rsfs(cAlias)
    SCAN
        FOR i=1 TO ALEN(afs)
            rs = EVALUATE(IIF(cAlias=="pjf_xxdm", "1",    afs[i]+"zrs"))
            fs = EVALUATE(IIF(cAlias=="pjf_xxdm", afs[i], afs[i]+"pjf"))
            IF fs != 0
                REPLACE (cAlias+"."+afs[i]+"zrs") WITH EVALUATE(cAlias+"."+afs[i]+"zrs") + rs,;
                        (cAlias+"."+afs[i]+"pjf") WITH EVALUATE(cAlias+"."+afs[i]+"pjf") + fs
            ENDIF
        ENDFOR
    ENDSCAN
ENDFUNC

    * 统计平均分
FUNCTION tj_pjf(cAlias)
    SELECT (cAlias)
    SCAN     
        FOR i=1 TO ALEN(afs)
            rs = EVALUATE(afs[i]+"zrs")
            fs = EVALUATE(afs[i]+"pjf")
            IF rs != 0
                REPLACE (afs[i]+"pjf") WITH fs/rs
            ENDIF
        ENDFOR
    ENDSCAN
ENDFUNC

    * 统计 联考名次、本市名次、本县名次
FUNCTION tj_mc(kmm, cAlias)
    eKey = kmm+"pjf"
    SELECT (cAlias)
    INDEX on &eKey TAG kmm DESCENDING
    tj_lkpx(kmm)        &&联考名次
    INDEX on dsdm*1000+&eKey TAG kmm DESCENDING
    tj_bspx(kmm)        &&本市名次  
    IF cAlias == "pjf_xxdm"
        INDEX on xqdm*1000+&eKey TAG kmm DESCENDING
        tj_bxpx(kmm)    &&本县名次
    ENDIF
ENDFUNC

    * 联考名次
FUNCTION tj_lkpx(kmm)
    m  = 1
    n  = 1
    fs = -1
    SCAN
        IF EVALUATE(kmm+"pjf") != fs
            fs = EVALUATE(kmm+"pjf")
            m  = n
        ENDIF
        n = n + 1
        REPLACE (kmm+"lkpx") WITH m
    ENDSCAN
ENDFUNC

    * 本市名次
FUNCTION tj_bspx(kmm)
    m  = 1
    n  = 1
    fs = -1
    dm = 0
    SCAN
        IF dsdm != dm
            dm = dsdm
            m = 1
            n = 1
        ENDIF
        IF EVALUATE(kmm+"pjf") != fs
            fs = EVALUATE(kmm+"pjf")
            m  = n
        ENDIF
        n = n + 1
        REPLACE (kmm+"bspx") WITH m
    ENDSCAN
ENDFUNC

    * 本县名次
FUNCTION tj_bxpx(kmm)
    m  = 1
    n  = 1
    fs = -1
    dm = 0
    SCAN
        IF xqdm != dm
            dm = xqdm
            m = 1
            n = 1
        ENDIF
        IF EVALUATE(kmm+"pjf") != fs
            fs = EVALUATE(kmm+"pjf")
            m  = n
        ENDIF
        n = n + 1
        REPLACE (kmm+"bxpx") WITH m
    ENDSCAN
ENDFUNC
#14
schtg2023-08-17 05:20
回复 13楼 吹水佬
非常感谢!
#15
王咸美2023-08-20 08:53
原始数据表无法下载,程序无法学习消化,很遗憾!
#16
jinanshui2023-08-21 01:48
回复 13楼 吹水佬
吹版主,运行了很长时间,不出结果呢,不知什么原因,谢谢勤劳的版主
#17
吹水佬2023-08-21 10:23
以下是引用jinanshui在2023-8-21 01:48:14的发言:

吹版主,运行了很长时间,不出结果呢,不知什么原因,谢谢勤劳的版主

1分钟左右吧
#18
jinanshui2023-08-21 16:25
吹版,您好,我试了好多次,怎么一直运行,停不下来,i5,16G内存,vfp9.0,请您看看,谢谢,我是个大菜鸟。
只有本站会员才能查看附件,请 登录


[此贴子已经被作者于2023-8-21 16:29编辑过]

#19
吹水佬2023-08-23 18:06
以下是引用jinanshui在2023-8-21 16:25:56的发言:

吹版,您好,我试了好多次,怎么一直运行,停不下来,i5,16G内存,vfp9.0,请您看看,谢谢,我是个大菜鸟。


cj表与prg路径相同,并设置prg为当前默认路径。
找不到cj表,测试不了。
#20
吹水佬2023-08-24 08:51
回复 18楼 jinanshui
LZ的数据在下载频道,见1楼连接
测试用了50几秒(i3 U、16G ram、ssd HD)
只有本站会员才能查看附件,请 登录

只有本站会员才能查看附件,请 登录



[此贴子已经被作者于2023-8-24 08:53编辑过]

#21
bdx8082023-08-24 16:00
学习了,谢谢!
#22
jinanshui2023-08-25 06:04
回复 20楼 吹水佬
谢谢版主,我再试试。
#23
jinanshui2023-08-25 07:28
版主老师,这是什么情况,谢谢,我是大菜鸟,多麻烦您了。
只有本站会员才能查看附件,请 登录
#24
吹水佬2023-08-27 09:13
回复 23楼 jinanshui
是不是重写文件的提示
试在开始加句:
SET SAFETY OFF
#25
jinanshui2023-08-27 17:31
回复 24楼 吹水佬
我试试,谢谢您
1