用户管理  |   用户注册                                                                                    首 页软件下载教程中心办公指南flash动画文档下载办公公文

www.4oa.com - 中科软件园

投递文章 用户管理 投稿指南 资讯通告 :
站内搜索: 您的位置中科软件园 > 教程中心 > 数据库类 > FoxPro > 基础教程 > 教程内容

group by分组的应用

2005-11-6 19:43:48  来源:本站整理  作者:佚名 【 投递文章
内容提要:第五节groupby分组的应用首先先说说分组是怎样工作的。举个例子:表:temp1有以下记录:bhslaaa1aaa4ccc2bbb5aaa9bbb7现在要统计一下temp1有中多少种编号,各种编号的...

第五节 group by分组的应用

首先先说说分组是怎样工作的。举个例子:

表:temp1有以下记录:

bhslaaa1aaa4ccc2bbb5aaa9bbb7

现在要统计一下temp1有中多少种编号,各种编号的总数量又是多少。很明显,这是使用分组。

sele bh,sum(sl) as total_sl ;  from temp1 ;  grou by bh ;  orde by bh ;  into curs temp2

命令的运行过程就象投票选举中的点票过程一样。它中间到底是采用什么样的技术来储存中间结果我不知道,但不这重要,我现在假设它使用临时表(实际上我想不大可能),这样对结果没影响,但又容易理解。

1、是逐个扫描记录。每遇到一个新的编号,就为这个编号建立一个临时表(再次重申,使用临时表只是我的假设布局,真正的处理方法我不知道),然后把这个记录的内容放进对应的临时表中去。如果不是新编号,就直接把记录内容放进对应的临时表中去。

2、全部记录扫描完了,各种编号对应的临时表也产生了,现在就是对每一个临时表采用sum()进行统计了。比如编号为"aaa"的临时表是cursor1,那它的内容就是:

Aaa1Aaa4Aaa9

现在进行sum()统计了,它的效果就相当于sele bh,sum(sl) as total_sl from cursor1。每一个编号的临时表都要进行这样的sum()统计,然后把每个编号的统计结果联合起来,就想使用union一样,最后得出的结果就是:

aaa14ccc2bbb12

3、然后再给bh排序,结果就是:

aaa14bbb12ccc2

看了上面那个例子,再看下面这条命令,想必也可以理解了吧:

sele cpk.cpbh,cpk.cpmc,sum(iif(isnull(thdmx.thsl),0,thdmx.thsl) as total_thsl ;  from cpk left join thdmx ;    on cpk.cpbh=thdmx.cpbh ;  grou by cpk.cpbh ;  orde by cpk.cpbh ;  into curs temp1 

产品表左联接提货明细表,这样没有提过的产品,在联接后的临时表中,对应的提货数量就是个null值。到了分组,第一步完成后,生成的临时表中也仍然有null值,所以在第二步进行sum命令时,就要使用iif(isnull())来过滤了。过滤的结果就是把null值改为0,其它的不变,然后再由sum进行汇总。最后第三步再排序,结果就出来了。

以上是分组的最基本用法。现在说说分组的一些古怪用法。

一、使用recn()。例子一:

有种情况,一大段本来是应该连续的号码,但中间地漏掉了一些号码,现在要把这些漏了的号码找出来。恐怕很多人,一来就是使用scan endscan,再加上一些中间变量以作为判断依据,最后写成的代码有一大段,运行起来慢得要死。但如果采用以下这种方法,我想即使它不是最好,但也是很好的了。数据如下:

1、6、3、5、2、7、9、10、15、16

在这些数据当中,要找出漏掉了的4、8、11、12、13、14。

1、首先排序

sele bh from temp1 orde by bh into curs temp1

结果是:

1、2、3、5、6、7、9、10、15、16

如果源表中的物理记录顺序和号码的顺序一样就不用做这一步了。

2、取temp1中各个记录的recn(),即记录号,然后把编号减去记录号

sele bh,val(bh-recn()) as aa from temp1 into curs temp2

结果就是:

Bhaa10203051617192102156166

3、对aa使用分组,取每组中最小的bh和最大的bh

sele min(bh) as minbh,max(bh) as maxbh from temp2 grou by aa into curs temp3

结果如下:

minbhmaxbh13579101516

4、现在结果很明显了,某个记录的minbh跟它上面那个记录的maxbh中间相差的,就是漏掉的号码。现在才使用scan endscan就容易了。

以上方法适用于数据量大、第三步的结果比源表少很多记录的情况下才会发挥效果。因为scan的速度不能和Select - SQL相比,何况它还要作条件判断。虽然这种方法使用了二条全遍历的SQL命令,但这是没过滤条件的SQL命令,速度是很快的,只是分组要多点时间而已。同时只适用于编号没有重复的情况。如果编号有重复,那在第一步的时候,就要使用:

sele bh from temp1 goru by bh orde by bh into curs temp1

把多余的编号去掉。如果想了解那些编号是重复的,就可以使用:

sele bh,coun(bh) as aa from temp1 grou by bh orde by bh havi aa>1 into curs temp1

结果就是重复的编号,对应的aa字段就是重复的次数。

在第二步,好象可以不用二条命令就可以得出结果了,只是暂时还没想到,不知各位对些有什么看法。

上面这种方法有个缺点:就是使用了sum()函数,而它是只能统计数值型的数据,其它字符型、日期型等是不能统计的。所以如果想把一个表中所有记录的产品名称都串起来,变成一个字符串,那是不能的。但对于日期型,变通一下,有时还是可以使用的。

二、日期相减的结果是数值,从而可以使用sum()函数。例子二

编号名称入库日期1网卡2000.09.021网卡2000.09.031网卡2000.09.052vfp2000.09.052vfp2000.09.06

说明:把编号和名称相同,入库日期相间为1的记录合并为一条,并加入另一个表里,如结果:

编号     名称   入库日期        (表2和表1结构一样)1网卡2000.09.031网卡2000.09.052vfp2000.09.06

要完成上面的要求,用两个步骤:

1、sele * from 表1 orde by 名称,入库日期 into curs temp12、sele 编号,名称,max(入库日期), 入库日期-recn() as dd;   from temp1 ;   grou by 名称,dd ;   into curs temp2

问题的关键是那个"入库日期-recn() as dd",因为已经按日期按好了顺序,所以9月2号减1和9月3号减2的结果都是相同的,但9月5号减3就是另外一个数了,所以这样就把这些日期分开了,就可以用分组了。假设表内容如下:(xm是字符类型,其中的1代表上午上班,2上午下班,3、4如此类推)

这个例子,到在处理第二步的时候,其实就跟第一个例子一样了,都是把一个字段减去记录号,然后根据结果进行分组。

例子三:某员工某月的打卡记录temp1如下:

打卡时间SJ项目XM状态ZT2000/09/1308:01:00AM1On time2000/09/1312:00:00AM2On time2000/09/1302:00:00PM3On time2000/09/1305:59:00PM4Early 2000/09/1208:00:00AM1On time2000/09/1212:00:00AM2On time2000/09/1202:00:00PM3On time2000/09/1206:00:00PM4On time2000/09/1408:00:00AM1On time2000/09/1412:00:00AM2On time2000/09/1402:01:00PM3Later 2000/09/1406:00:00PM4On time2000/09/1508:00:00AM1On time2000/09/1512:00:00AM2On time2000/09/1502:00:00PM3On time2000/09/1506:00:00PM4On time

xm中的1、2、3、4分别代表早上上班、早上下班、下午上班

[1] [2]  下一页

(评论内容只代表网友观点,与本站立场无关!)[ 全部评论 ]

网友评论:

    用户名:

    评   分:100分 85分 70分 55分 40分 25分 10分 0分

    内 容:

                 (注“”为必填内容。) 验证码: 验证码,看不清楚?请点击刷新验证码

关于本站 - 网站帮助 - 广告合作 - 下载声明 - 友情连接 - 网站地图 -有事点这里