| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 4228 人关注过本帖, 1 人收藏
标题:不同分数段人数统计的简易方法
取消只看楼主 加入收藏
sdta
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
来 自:江苏省连云港市
等 级:版主
威 望:335
帖 子:9841
专家分:27213
注 册:2012-2-5
结帖率:88.24%
收藏(1)
 问题点数:0 回复次数:10 
不同分数段人数统计的简易方法
程序代码:
* 不同分数段人数统计,分数为整数
* 测试表
CREATE CURSOR CJK (CJ N(3))
INSERT INTO CJK VALUES (15)
INSERT INTO CJK VALUES (28)
INSERT INTO CJK VALUES (35)
INSERT INTO CJK VALUES (8)
INSERT INTO CJK VALUES (2)
INSERT INTO CJK VALUES (4)
INSERT INTO CJK VALUES (9)
INSERT INTO CJK VALUES (64)
INSERT INTO CJK VALUES (75)
INSERT INTO CJK VALUES (65)
INSERT INTO CJK VALUES (125)
INSERT INTO CJK VALUES (115)
INSERT INTO CJK VALUES (27)
INSERT INTO CJK VALUES (88)

SELECT MIN(CJ) CJ1,MAX(CJ) CJ2 FROM CJK INTO ARRAY ACJ
* 获取最低分及最高分
NMIN=ACJ(1,1)
NMAX=ACJ(1,2)
* 如果设置10分为一个分数段
NUM=10 && 此处可以改为任意数值
NMIN=FLOOR(NMIN/NUM)*NUM   && 最低分数段的开始分
NMAX=IIF(MOD(NMAX,NUM)=0,(CEILING(NMAX/NUM)+1)*NUM,CEILING(NMAX/NUM)*NUM) && 最高分数段的终止分

* 分数段生成
CREATE CURSOR FSD (FS1 N(3),FS2 N(3)) && 保存分数段的临时表
FOR I=NMIN TO INT(NMAX/NUM)-1
    IF I=NMIN
       INSERT INTO FSD VALUES (I,(I+1)*NUM-1)
    ELSE
       INSERT INTO FSD VALUES (NUM1,(I+1)*NUM-1)
    ENDIF
    NUM1=(I+1)*NUM
ENDFOR
SELECT *,000 RS FROM FSD WHERE .F. INTO CURSOR CJTJ READWRITE && 保存统计结果的临时表
SELECT FSD
SCAN
   INSERT INTO CJTJ SELECT FSD.FS1,FSD.FS2,COUNT(*) RS FROM CJK WHERE BETWEEN(CJK.CJ,FSD.FS1,FSD.FS2)
ENDSCAN
SELECT CJTJ
BROWSE


[ 本帖最后由 sdta 于 2014-3-14 19:52 编辑 ]
收到的鲜花
  • tlliqi2014-03-14 19:56 送鲜花  20朵   附言:方法不错
搜索更多相关主题的帖子: 测试表 color 统计 
2014-03-14 19:35
sdta
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
来 自:江苏省连云港市
等 级:版主
威 望:335
帖 子:9841
专家分:27213
注 册:2012-2-5
收藏
得分:0 
从实际工作出发,每个学校对每门课程分数段的要求也不一样,个人认为,最科学的方法应该是设计一张分数段表,里面保存不同的分数段。

坚守VFP最后的阵地
2014-03-18 15:12
sdta
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
来 自:江苏省连云港市
等 级:版主
威 望:335
帖 子:9841
专家分:27213
注 册:2012-2-5
收藏
得分:0 
根据大家反馈的情况,找了一个成绩表,重新写了段不同分数段人数统计的代码
cj.rar (10.89 KB)


程序代码:
*-创建一个分数段标准表,这个标准表可以是自由表,也可以是临时表
CREATE CURSOR bz (下限 N(3),上限 N(3))
NUM=10 && 10分一个分数段,或者手工建一个自由表,前提是分数必须为整数
FSD=80 && 共设置FSD个分数段
FOR I=1 TO FSD
    IF I=1
       INSERT INTO BZ VALUES (0,NUM-I)
    ELSE
       INSERT INTO BZ VALUES (NUM1+1,NUM1+NUM)
    ENDIF
    NUM1=上限
ENDFOR

CREATE CURSOR T2 (班级 C(4),课程 C(10),档次 C(10),人数 N(4)) && 保存统计结果的临时表

SELECT 班级,[语文] 课程,语文 成绩 FROM CJ ;
UNION ALL SELECT 班级,[数学] SX,数学 FROM CJ ;
UNION ALL SELECT 班级,[综合] ZH,综合 FROM CJ ;
UNION ALL SELECT 班级,[英语] YY,英语 FROM CJ ;
UNION ALL SELECT 班级,[总分] ZF,总分 FROM CJ INTO CURSOR T0

SELECT BZ
SCAN
   INSERT INTO T2 SELECT 班级,课程,PADL(BZ.下限,3,[0])+[-]+PADL(BZ.上限,3,[0]),COUNT(*) FROM T0 GROUP BY 1,2 WHERE BETWEEN(成绩,BZ.下限,BZ.上限)
ENDSCAN

CREATE CURSOR FSTJ (档次 C(7),语文 N(3),数学 N(3),综合 N(3),英语 N(3),总分 N(3))
INSERT INTO FSTJ (档次) SELECT PADL(BZ.下限,3,[0])+[-]+PADL(BZ.上限,3,[0]) 档次 FROM BZ
SELECT DISTINCT 班级 FROM T0 INTO CURSOR BJ
SCAN
   BJ1=班级
   BJ=[BJ]+ALLTRIM(班级) &&以班级名称做为表名称
   SELECT *,000 小计 FROM FSTJ INTO TABLE &BJ
   UPDATE &BJ SET 语文=T2.人数 FROM &BJ INNER JOIN T2 ON &BJ..档次=T2.档次 AND T2.课程=[语文] AND T2.班级==BJ1
   UPDATE &BJ SET 数学=T2.人数 FROM &BJ INNER JOIN T2 ON &BJ..档次=T2.档次 AND T2.课程=[数学] AND T2.班级==BJ1
   UPDATE &BJ SET 综合=T2.人数 FROM &BJ INNER JOIN T2 ON &BJ..档次=T2.档次 AND T2.课程=[综合] AND T2.班级==BJ1
   UPDATE &BJ SET 英语=T2.人数 FROM &BJ INNER JOIN T2 ON &BJ..档次=T2.档次 AND T2.课程=[英语] AND T2.班级==BJ1
   UPDATE &BJ SET 总分=T2.人数 FROM &BJ INNER JOIN T2 ON &BJ..档次=T2.档次 AND T2.课程=[总分] AND T2.班级==BJ1
   SELECT (BJ)
   REPLACE ALL 小计 WITH 语文+数学+综合+英语
   INSERT INTO (BJ) SELECT [合计],SUM(语文),SUM(数学),SUM(综合),SUM(英语),SUM(总分),SUM(小计) FROM (BJ)
ENDSCAN


[ 本帖最后由 sdta 于 2014-3-18 18:25 编辑 ]

坚守VFP最后的阵地
2014-03-18 18:13
sdta
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
来 自:江苏省连云港市
等 级:版主
威 望:335
帖 子:9841
专家分:27213
注 册:2012-2-5
收藏
得分:0 
在15楼的基础上,对代码做了部分修改
程序代码:
*-创建一个分数段标准表,这个标准表可以是自由表,也可以是临时表
CREATE CURSOR bz (下限 N(3),上限 N(3))
NUM=10 && 10分一个分数段,或者手工建一个自由表,前提是分数必须为整数
FSD=80 && 共设置FSD个分数段
FOR I=1 TO FSD
    IF I=1
       INSERT INTO BZ VALUES (0,NUM-I)
    ELSE
       INSERT INTO BZ VALUES (NUM1+1,NUM1+NUM)
    ENDIF
    NUM1=上限
ENDFOR

* 统一格式,便于统计
SELECT 班级,[语文] 课程,语文 成绩,SPACE(7) 分数段 FROM CJ ;
UNION ALL SELECT 班级,[数学] SX,数学,SPACE(7) 分数段 FROM CJ ;
UNION ALL SELECT 班级,[综合] ZH,综合,SPACE(7) 分数段 FROM CJ ;
UNION ALL SELECT 班级,[英语] YY,英语,SPACE(7) 分数段 FROM CJ ;
UNION ALL SELECT 班级,[总分] ZF,总分,SPACE(7) 分数段 FROM CJ INTO CURSOR T0 READWRITE
*BROWSE && 可以查看内容

* 划分分数段
UPDATE T0 SET 分数段=PADL(BZ.下限,3,[0])+[-]+PADL(BZ.上限,3,[0]) FROM BZ WHERE BETWEEN(T0.成绩,BZ.下限,BZ.上限)

* 统计不同分数段的人数
SELECT 班级,课程,分数段,COUNT(*) 人数 FROM T0 GROUP BY 1,2,3 INTO CURSOR T2

* 生成统计结果的模板
CREATE CURSOR FSTJ (分数段 C(7),语文 N(3),数学 N(3),综合 N(3),英语 N(3),总分 N(3))
INSERT INTO FSTJ (分数段) SELECT PADL(BZ.下限,3,[0])+[-]+PADL(BZ.上限,3,[0]) 档次 FROM BZ

* 生成不重复的班级名称,用于数据统计
SELECT DISTINCT 班级 FROM T0 INTO CURSOR BJ

* 生成最后的统计结果
SCAN
   BJ1=班级
   BJ=[BJ]+ALLTRIM(班级)
   SELECT *,000 小计 FROM FSTJ INTO TABLE &BJ
   UPDATE &BJ SET 语文=T2.人数 FROM &BJ INNER JOIN T2 ON &BJ..分数段=T2.分数段 AND T2.课程=[语文] AND T2.班级==BJ1
   UPDATE &BJ SET 数学=T2.人数 FROM &BJ INNER JOIN T2 ON &BJ..分数段=T2.分数段 AND T2.课程=[数学] AND T2.班级==BJ1
   UPDATE &BJ SET 综合=T2.人数 FROM &BJ INNER JOIN T2 ON &BJ..分数段=T2.分数段 AND T2.课程=[综合] AND T2.班级==BJ1
   UPDATE &BJ SET 英语=T2.人数 FROM &BJ INNER JOIN T2 ON &BJ..分数段=T2.分数段 AND T2.课程=[英语] AND T2.班级==BJ1
   UPDATE &BJ SET 总分=T2.人数 FROM &BJ INNER JOIN T2 ON &BJ..分数段=T2.分数段 AND T2.课程=[总分] AND T2.班级==BJ1
   SELECT (BJ)
   REPLACE ALL 小计 WITH 语文+数学+综合+英语
   INSERT INTO (BJ) SELECT [合计],SUM(语文),SUM(数学),SUM(综合),SUM(英语),SUM(总分),SUM(小计) FROM (BJ)
BROWSE
ENDSCAN




坚守VFP最后的阵地
2014-03-18 18:58
sdta
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
来 自:江苏省连云港市
等 级:版主
威 望:335
帖 子:9841
专家分:27213
注 册:2012-2-5
收藏
得分:0 
以下是引用TonyDeng在2014-3-18 18:40:06的发言:

仍然有硬編碼呢
有话直说

坚守VFP最后的阵地
2014-03-18 19:00
sdta
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
来 自:江苏省连云港市
等 级:版主
威 望:335
帖 子:9841
专家分:27213
注 册:2012-2-5
收藏
得分:0 
以下是引用TonyDeng在2014-3-18 19:09:26的发言:

不是說了麽,就是有硬編碼。
说清楚,否则要打屁股了

坚守VFP最后的阵地
2014-03-18 19:10
sdta
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
来 自:江苏省连云港市
等 级:版主
威 望:335
帖 子:9841
专家分:27213
注 册:2012-2-5
收藏
得分:0 
听君一席话,胜读十年书。
我再看看

坚守VFP最后的阵地
2014-03-18 20:12
sdta
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
来 自:江苏省连云港市
等 级:版主
威 望:335
帖 子:9841
专家分:27213
注 册:2012-2-5
收藏
得分:0 
以下是引用TonyDeng在2014-3-18 19:25:53的发言:

隨便說個例子吧,代碼裡面出現了具體的、數目有限的科目名稱,而當設計的數據表科目有增減或名稱變動時,就要改代碼了,這叫硬編碼。後面那一堆UPDATE,就是很明顯的微小差別語句重複,很礙眼的。
这个问题我也考虑过了,先写出代码,再修改为相对通用的代码。

坚守VFP最后的阵地
2014-03-18 20:17
sdta
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
来 自:江苏省连云港市
等 级:版主
威 望:335
帖 子:9841
专家分:27213
注 册:2012-2-5
收藏
得分:0 
CJ.rar (10.88 KB)

再版

程序代码:
SET TALK OFF
*-创建一个分数段标准表,这个标准表可以是自由表,也可以是临时表
CREATE CURSOR bz (下限 N(3),上限 N(3))
NUM=10 && 10分一个分数段,或者手工建一个自由表,前提是分数必须为整数
FSD=80 && 按照总成绩的满分设置分数段,共设置FSD个分数段
FOR I=1 TO FSD
    IF I=1
       INSERT INTO BZ VALUES (0,NUM-I)
    ELSE
       INSERT INTO BZ VALUES (NUM1+1,NUM1+NUM)
    ENDIF
    NUM1=上限
ENDFOR

* 统一格式,便于统计(列记录转换为行记录),获取字段数,表中各门功课成绩排在所有非成绩字段的后面
SELECT * FROM CJ INTO CURSOR CJ1
NZDS=AFIELDS(AZDM,[CJ1])
CSQL=[]
FOR I=2 TO NZDS && 本示例中,从第2个字段开始为各门课程的成绩字段
    CSQL=CSQL+IIF(I>2,[UNION ALL ],[])+[SELECT 班级,']+AZDM[I,1]+[' 课程,]+AZDM[I,1]+[ 成绩]+[,' ]+SPACE(7)+[' 分数段 FROM CJ ]+IIF(I=NZDS,[INTO CURSOR CJ2 READWRITE],[])
ENDFOR
* 执行SQL命令
EXECSCRIPT(CSQL)

* 划分分数段
UPDATE CJ2 SET 分数段=PADL(BZ.下限,3,[0])+[-]+PADL(BZ.上限,3,[0]) FROM BZ WHERE BETWEEN(CJ2.成绩,BZ.下限,BZ.上限)

* 统计不同分数段(按课程分)的人数
SELECT 班级,课程,分数段,COUNT(*) 人数 FROM CJ2 GROUP BY 1,2,3 INTO CURSOR CJ3

* 生成不同班级,不同课程的分数段
SELECT A.*,PADL(B.下限,3,[0])+[-]+PADL(B.上限,3,[0]) 分数段 FROM (SELECT 班级,课程 FROM CJ3 GROUP BY 1,2) A,BZ B INTO CURSOR BJKC

* 填补每门课程不存在的分数段
SELECT A.班级,A.课程,A.分数段,NVL(B.人数,0) 人数 FROM BJKC A LEFT JOIN CJ3 B ON A.分数段=B.分数段 AND A.班级=B.班级 AND A.课程=B.课程 INTO CURSOR CJ4

* 生成分数段最后统计表(行记录转换为列记录)
SELECT 课程 FROM CJ3 GROUP BY 1 INTO CURSOR KC
CSQL="SELECT 班级,分数段"
SCAN
   CSQL=CSQL+",CAST(SUM(IIF(ALLTRIM(课程)=='"+ALLTRIM(课程)+"',人数,0)) AS N(4)) AS "+ALLTRIM(课程)+;
    IIF(RECNO()<RECCOUNT(),[],[,0000 小计 FROM CJ4 GROUP BY 1,2 INTO CURSOR CJTJB READWRITE])
ENDSCAN
EXECSCRIPT(CSQL)

* 行记录计算
XJ=[]
FOR I=3 TO FCOUNT()-2 && 从第三个字段开始统计行记录小计,最后两个字段分别是 总分、小计 字段
    XJ=XJ+(FIELD(I))+IIF(I<FCOUNT()-2,[+],[])
ENDFOR
REPLACE ALL [小计] WITH &XJ

* 列记录计算
NZDS=AFIELDS(AZDM,[CJTJB])
CSQL=[SELECT ALLTRIM(班级)+'合' 班级,SPACE(7) 分数段]
SET ENGINEBEHAVIOR 70
FOR I=3 TO NZDS
   CSQL=CSQL+",CAST(SUM("+AZDM[I,1]+") AS N(4)) AS "+AZDM[I,1]+IIF(I<NZDS," "," FROM CJTJB GROUP BY 班级")
ENDFOR
CSQL=[INSERT INTO CJTJB ]+CSQL
EXECSCRIPT(CSQL)
SELECT * FROM CJTJB ORDER BY 1 INTO CURSOR CJTJ READWRITE
FOR I=3 TO FCOUNT()
    IF TYPE(FIELD(I))="N"
       *--- 清空数值型字段内容为"0"的记录
       BLANK FIELD (FIELD(I)) FOR EVALUATE(FIELD(I))=0
    ENDIF
ENDFOR
BROWSE
SET ENGINEBEHAVIOR 90


[ 本帖最后由 sdta 于 2014-3-19 00:54 编辑 ]

坚守VFP最后的阵地
2014-03-18 23:51
sdta
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
来 自:江苏省连云港市
等 级:版主
威 望:335
帖 子:9841
专家分:27213
注 册:2012-2-5
收藏
得分:0 
按最后一次代码运行

坚守VFP最后的阵地
2014-03-21 10:35
快速回复:不同分数段人数统计的简易方法
数据加载中...
 
   



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

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