<% dim ModuleName,InfoID,ChannelShortName,CorrelativeArticle,InstallDir,ChannelDir,Keyword,PageTitle,ArticleIntro,Articlecontent Keyword=stripHTML("数据库.FoxPro.基础") PageTitle=stripHTML("select - SQL的工作流程") ArticleIntro=stripHTML("") Articlecontent=stripHTML("第一节 select - SQL的工作流程  再复杂的SQL命令,也是由一些基本的结构组成的。所以在看、去做一条很复杂的SQL命令时,要会把它一级一级的折分,最…") ModuleName = stripHTML("classical") InfoID = stripHTML("28938") ChannelShortName=stripHTML("文章") InstallDir=stripHTML("http://www.77169.com/") ChannelDir=stripHTML("classical") %> select - SQL的工作流程 - 华盟网 - http://www.77169.com  <% Function stripHTML(strHTML) 'Strips the HTML tags from strHTML Dim objRegExp, strOutput Set objRegExp = New Regexp objRegExp.IgnoreCase = True objRegExp.Global = True objRegExp.Pattern = "<.+?>" 'Replace all HTML tag matches with the empty string strOutput = objRegExp.Replace(strHTML, "") 'Replace all < and > with < and > strOutput = Replace(strOutput, "<", "<") strOutput = Replace(strOutput, ">", ">") strOutput = Replace(strOutput,Chr(34),Chr(39)) stripHTML = strOutput 'Return the value of strOutput Set objRegExp = Nothing End Function %> "> 
您现在的位置: 华盟网 >> 知识库 >> 数据库 >> FoxPro >> 基础教程 >> 正文

select - SQL的工作流程

2005/8/29 作者:unknown 来源: unknown
导读 <% if len(ArticleIntro)<3 then Response.Write Articlecontent 'Response.Write "Articlecontent" else Response.Write ArticleIntro 'Response.Write "ArticleIntro" end if %>

第一节 select - SQL的工作流程

再复杂的SQL命令,也是由一些基本的结构组成的。所以在看、去做一条很复杂的SQL命令时,要会把它一级一级的折分,最后折成最简单的,这样才容易理解。而这个折分过程,如果不熟悉SQL命令的工作流程,那就比较难折分了。

大体来说,它是先根据联接条件(即联接条件on中的表达式),把几个的表合成一个临时表,然后根据where中的条件进行过滤,过滤出来的结果根据分组条件再把这个临时表分成一组一组,然后对分别对些组进行字段计算,最后又得出一个临时表,然后又根据having中的条件对这个临时表进行再次过滤,最后输入到指定的地方,如数组、表等。它中间生成的临时表对用户来说,是完全透明的,用户是不可能使用、也不能创建,它是由系统自己创建、自己使用、自己撤除,完全不受用户控制的。我举个例子:有二个表:提货单thd、提货单明细thdmx:

thd
提货单号	提货日期

thdbh	thrq

01	2000/01/02

02	2000/01/15

03	2000/02/01

thdmx

提货单号	产品编号	提货数量

thdbh	cpbh	Thsl

01	001	5

01	003	15

01	005	12

02	001	13

02	002	14

02	005	20

03	002	14

现在有个要求:要统计day1=2000/01/01至day2=2000/01/20这段时间内,提货数量大于10的产品有那些,它们各自的总提货量是多少。命令如下:

sele cpbh,sum(thsl) ;

  from thd join thdmx ;

    on thd.thdbh=thdmx.thdbh.and.thsl>10.and.betw(thrq,day1,day2) ;

  grou by cpbh ;

  into curs temp1

为什么把thsl>0和betw(thrq,day1,day2)这二个条件表达式放在on那里,参见on、where与having的区别。它的工作流程:

首先根据on中的过滤条件,对所涉及的表进行预处理。过程如下:

两个表根据thd.thdbh=thdmx.thdbh进行合并,变成一个这样的临时表:

thdbh1	thrq		thdbh2	Cpbh	thsl

01	2000/01/02	01	001	5

01	2000/01/02	01	003	15

01	2000/01/02	01	005	12

01	2000/01/02	02	001	13

01	2000/01/02	02	002	14

01	2000/01/02	02	005	20

01	2000/01/02	03	002	14

02	2000/01/15	01	001	5

02	2000/01/15	01	003	15

02	2000/01/15	01	005	12

02	2000/01/15	02	001	13

02	2000/01/15	02	002	14

02	2000/01/15	02	005	20

02	2000/01/15	03	002	14

03	2000/02/01	01	001	5

03	2000/02/01	01	003	15

03	2000/02/01	01	005	12

03	2000/02/01	02	001	13

03	2000/02/01	02	002	14

03	2000/02/01	02	005	20

03	2000/02/01	03	002	14

合并是按照笛卡尔积进行计算的,即二个表都有10个记录,那积就会有10*10=100个记录,这是很历害的。但因为on条件中有过滤条件,所以VFP并不会这么笨,它会把符合这个条件的记录才放到临时表中的。这样,结果就少了很多记录了。结果出来后,再根据on后来的过滤条件thsl>10.and.betw(thrq,day1,day2)进行过滤,这样thsl大于10而且提货日期是在day1至day2的记录最后才出现在这一步的临时表中。

01	2000/01/02	01	003	15

01	2000/01/02	01	005	12

02	2000/01/15	02	001	13

02	2000/01/15	02	002	14

02	2000/01/15	02	005	20

现在轮到分组了。根据产品编号进行分组,它具体的分组方法我不知道是怎样,我想可能是这样的:

象在投票选举时点票那样,在上面那个临时表从头到尾扫一次,每经过一记录时,它就看一下,当前的产品编号是不是一个新的组,如果是就新增一个分组记号,相当于新增加一个被选举人,然后在它下面加上thsl的值,全部记录数完了,就看看有多少个分组标记,各个分组又有多少thsl。结果就是以下的样子:

001	13

002	14

003	15

005	32

这就是这条命令的结果了。然后把它生成一个cursor表,命令就完成了。如果再深入一点,把要求改成某段时间内全部产品的提货情况,如果没有进货记录,那就是0,一样要出现在结果表里。

这时,就涉及到三个表了:产品表cpb、提货表thd、提货明细表thdmx。我们先用内联接来把这三个表联接起来。

sele cpb.cpbh,cpb.cpmc,sum(iif(isnull(thdmx.thsl),0,thdmx.thsl)) as thsl ;

  from cpbh join thdmx ;

            join thd ;

    on cpbh.cpbh=thdmx.cpbh ;

    on thdmx.thdbh=thd.thdbh.and.betw(thd.thrq,day1,day2) ;

  grou by cpbh ;

  into curs temp1 

根据内联接的定义,即某个产品编号在产品表和提货明细表中都存在的记录,才会出现在结果表中,如果某种产品没有提货,那在提货明细表就没有这个记录,这样,也就不会出现在结果表中。那样就符合要求中的"全部产品"这个条件了。所以我们要把 产品表 左联接 提货明细表,这样不管这种产品有没有提货,它都会出现在结果表中,只是以null的值出现。但这个现象可以消除的。

命令过程也和上一个要求那样,先进行联接,只是这条命令的中间临时表比上面更大,因为是三个表的记录数相乘。但经过联接条件过滤后,就会剩下这些内容:

001	02	2000/01/15	02	001	13

002	02	2000/01/15	02	002	14

003	01	2000/01/02	01	003	15

004	null	null		null	null	null

005	01	2000/01/02	01	005	12

005	02	2000/01/15	02	005	20

然后也一样进行分组,分组时的判断过程也一样,只是在累加的时候有点不同:

sum(iif(isnull(thdmx.thsl),0,thdmx.thsl)),是先用isnull(thdmx.thsl)检查thsl是不是null,如果是,则iif()就返回0,如果不是,则返回thdmx.thsl。然后外层的sum()就根据iif()返回的数值进行累加,最后做为这个分组的累加值。

还有一种使用方法,说出来也可以加深命令当中的sum()函数的处理过程。

人事表rsb:

姓名xm	年龄age

张三	25

李四	32

王五	28

现在想统计一下各个年龄段(20-30,31-40)的人数是多少。

sele sum(iif(betw(age,20,30),1,0) as _20-30,sum(iif(betw(age,31,40),1,0) as _31-40 ;

  from rsb ;

  grou by zc ;

  into curs temp1

因为这条命令没有过滤条件、联接,所以不需事先预处理,一来就进行分组。和投票中点票一样,在"黑板"上写划出三列:

    zc        _20-30        _31-40

这样,在rsb中从头扫到尾时,每经过一记录时,都用iif(betw(age,20,30),1,0)检查这个人的年龄是不是处于20-30,如果是就在_20-30这一列下面加一横,否则就不加。第二个iif()也这样处理。如果当前的年龄是53,那二个iif()都是返回0,即二列都不加,相当于废票。全部记录都点完了,然后就用sum()进行合计了,结果就出来了。

因为二个sum()都是扫描完后再合计的,它不象sum命令。sum命令会移动记录指针,而sum()函数不会,所以不必怕使用这个函数会造成不良后果。而且二个iif()都有自己的判断条件,两者不互相重合,所以一个记录不会重复计算(除非你的命令设计错了。)

如果使用union参数把两条运算结果的格式一模一样的命令合在一起,那也是一样的。它是把其中的每一节select命令单独运行(它单独运行时的运行流程跟上面说的一样),最后才把每一节的结果首尾相接后,再根据最后那节的orde by进行排序。所以一条带union的SQL命令,只能有一个orde by。而每一节select命令,却可以有自己的grou by,它自己的grou by只对这一节有影响,是不会影响到其它节的运算的。更不会对最后结果有影响。

这里举个例子:我想统计一段时间内的提货、进货情况。这里要涉及到5个表:产品表、提货表、提货明细表、进货表、进货明细表:

sele cpbh,sum(thdmx.thsl) as thsl,100000-100000 as jhsl ;

  from thd join thdmx ;

    on thd.thdbh=thdmx.thdbh ;

  grou by cpbh ;

union ;

sele cpbh,0,sum(jhdmx.jhsl) ;

  from jhd join jhdmx ;

    on jhd.jhdbh=jhdmx.jhdbh ;

  grou by cpbh ;

  orde by cpbh ;

  into curs temp1

如果看了上面的解释,应该可以理解每一节SQL命令的意思。这里要说的是:

1、union要求前后两节SQL命令产生的表,在结构上要完全一样,包括字段的顺序也要一样。所以为了达到这个要求,在第一节,就要人为建立一个字段jhsl,而在第二节命令,也要建立一个字段thsl以对应。

2、用SQL产生的表,它不象crea table那样可以直接指定字段的类型、长度,而是在根据生成的临时表中第一个记录的长度来确定的。所在在第一节,如果不使用100000-100000而是直接使用0,这样产生的jhsl这个字段,它的长度就只有2个字节了。所以只有使用这种方法,才能使得这个字段的长度有7字节。在字符串也有这样情况,如果第一个记录的长度是12个字节,那以后的记录中,超过12个字节的内容就会给它去掉,这就是为什么有时在结果表中会出现字符串不完整的情况。解决方法也差不多,在字段列表那里人空加几个空格去。

 

                  微信群名称:华盟-黑白之道         华盟--黑白之道⑦QQ群: 9430885

  • 上一篇文章:

  • 下一篇文章:
  • 
    网友评论
      验证码
     
    

    关注

    分享

    0

    讨论

    2

    猜你喜欢

      <%=CorrelativeArticle%>

    论坛最新贴