公布MySQL 5.0 新特征教程 存储历程:第三讲
“对于MySQL数据库,无论是在开发方面,还是支持方面,现在有大量强大的MySQL学习教程可以选择。每一个新手开发者可以轻松地使用MySQL数据库进行开发。MySQLAB;翻译:陈朋奕TheNewSQLStatements新SQL语句
Variables变量
在复合语句中声明变量的指令是DECLARE。
(1)ExamplewithtwoDECLAREstatements
两个DECLARE语句的例子
CREATEPROCEDUREp8()
BEGIN
DECLAREaINT;
DECLAREbINT;
SETa=5;
SETb=5;
INSERTINTOtVALUES(a);
SELECTs1*aFROMtWHEREs1>=b;
END;///*IwontCALLthis*/
在过程当中界说的变量并非真实的界说,你只是在BEGIN/END块内界说了罢了(译注:也就是形参)。
注重这些变量和会话变量纷歧样,不克不及利用润色符@你必需分明的在BEGIN/END块中声明变量和它们的范例。
变量一旦声明,你就可以在任何能利用会话变量、笔墨、列名的中央利用。
(2)ExamplewithnoDEFAULTclauseandSETstatement
没有默许子句和设定语句的例子
CREATEPROCEDUREp9()
BEGIN
DECLAREaINT/*thereisnoDEFAULTclause*/;
DECLAREbINT/*thereisnoDEFAULTclause*/;
SETa=5;/*thereisaSETstatement*/
SETb=5;/*thereisaSETstatement*/
INSERTINTOtVALUES(a);
SELECTs1*aFROMtWHEREs1>=b;
END;///*IwontCALLthis*/
有良多初始化变量的办法。假如没有默许的子句,那末变量的初始值为NULL。你能够在任什么时候候利用SET语句给变量赋值。
(3)ExamplewithDEFAULTclause
含有DEFAULT子句的例子
CREATEPROCEDUREp10()
BEGIN
DECLAREa,bINTDEFAULT5;
INSERTINTOtVALUES(a);
SELECTs1*aFROMtWHEREs1>=b;
END;//
我们在这里做了一些改动,可是了局仍是一样的。在这里利用了DEFAULT子句来设定初始值,这就不必要把DECLARE和SET语句的完成分隔了。
(4)ExampleofCALL
挪用的例子
mysql>CALLp10()//
+--------+
|s1*a|
+--------+
|25|
|25|
+--------+
2rowsinset(0.00sec)
QueryOK,0rowsaffected(0.00sec)
了局显现了历程能一般事情
(5)Scope
感化域
CREATEPROCEDUREp11()
BEGIN
DECLAREx1CHAR(5)DEFAULTouter;
BEGIN
DECLAREx1CHAR(5)DEFAULTinner;
SELECTx1;
END;
SELECTx1;
END;//
如今我们来会商一下感化域的成绩。例子中有嵌套的BEGIN/END块,固然这是正当的。同时包括两个变量,名字都是x1,如许也是正当的。外部的变量在其感化域内享有更高的优先权。当实行到END语句时,外部变量消散,此时已在其感化域外,变量不再可见了,因而在存储历程外不再能找到这个声了然的变量,可是你能够经由过程OUT参数大概将其值指派给会话变量来保留其值。
挪用感化域例子的历程:
mysql>CALLp11()//
+-------+
|x1|
+-------+
|inner|
+-------+
+-------+
|x1|
+-------+
|outer|
+-------+
我们看到的了局时第一个SELECT语句检索到最内层的变量,第二个检索到第二层的变量
ConditionsandIF-THEN-ELSE前提式和IF-THEN-ELSE
1.
如今我们能够写一些包括前提式的例子:
CREATEPROCEDUREp12(INparameter1INT)
BEGIN
DECLAREvariable1INT;
SETvariable1=parameter1+1;
IFvariable1=0THEN
INSERTINTOtVALUES(17);
ENDIF;
IFparameter1=0THEN
UPDATEtSETs1=s1+1;
ELSE
UPDATEtSETs1=s1+2;
ENDIF;
END;//
这里是一个包括IF语句的历程。内里有两个IF语句,一个是IF语句ENDIF,另外一个是IF语句ELSE语句ENDIF。我们能够在这里利用庞大的历程,但我会只管使其复杂让你能更简单弄分明。
2.
CALLp12(0)//
我们挪用这个历程,传进值为0,如许parameter1的值将为0。
3.
CREATEPROCEDUREp12(INparameter1INT)
BEGIN
DECLAREvariable1INT;
SETvariable1=parameter1+1;<--
IFvariable1=0THEN
INSERTINTOtVALUES(17);
ENDIF;
IFparameter1=0THEN
UPDATEtSETs1=s1+1;
ELSE
UPDATEtSETs1=s1+2;
ENDIF;
END;//
这里变量variable1被赋值为parameter1加1的值,以是实行后变量variable1为1。
4.
CREATEPROCEDUREp12(INparameter1INT)
BEGIN
DECLAREvariable1INT;
SETvariable1=parameter1+1;
IFvariable1=0THEN<--
INSERTINTOtVALUES(17);
ENDIF;
IFparameter1=0THEN
UPDATEtSETs1=s1+1;
ELSE
UPDATEtSETs1=s1+2;
ENDIF;
END;//
由于变量variable1值为1,因而前提"ifvariable1=0"为假,
IF
……
ENDIF
被跳过,没有被实行。
5.
CREATEPROCEDUREp12(INparameter1INT)
BEGIN
DECLAREvariable1INT;
SETvariable1=parameter1+1;
IFvariable1=0THEN
INSERTINTOtVALUES(17);
ENDIF;
IFparameter1=0THEN<--
UPDATEtSETs1=s1+1;
ELSE
UPDATEtSETs1=s1+2;
ENDIF;
END;//
到第二个IF前提,判别了局为真,因而两头语句被实行了
6.
CREATEPROCEDUREp12(INparameter1INT)
BEGIN
DECLAREvariable1INT;
SETvariable1=parameter1+1;
IFvariable1=0THEN
INSERTINTOtVALUES(17);
ENDIF;
IFparameter1=0THEN
UPDATEtSETs1=s1+1;<--
ELSE
UPDATEtSETs1=s1+2;
ENDIF;
END;//
由于参数parameter1值即是0,UPDATE语句被实行。假如parameter1值为NULL,则下一条UPDATE语句将被实行如今表t中有两行,他们都包括值5,以是假如我们挪用p12,两行的值会酿成6。
7.
mysql>CALLp12(0)//
QueryOK,2rowsaffected(0.28sec)
mysql>SELECT*FROMt//
+------+
|s1|
+------+
|6|
|6|
+------+
2rowsinset(0.01sec)
了局也是我们所希冀的那样。
CASE指令
1.
CREATEPROCEDUREp13(INparameter1INT)
BEGIN
DECLAREvariable1INT;
SETvariable1=parameter1+1;
CASEvariable1
WHEN0THENINSERTINTOtVALUES(17);
WHEN1THENINSERTINTOtVALUES(18);
ELSEINSERTINTOtVALUES(19);
ENDCASE;
END;//
假如必要举行更多前提真假的判别我们可使用CASE语句。CASE语句利用和IF一样复杂。
我们能够参考下面的例子:
2.
mysql>CALLp13(1)//
QueryOK,1rowaffected(0.00sec)
mysql>SELECT*FROMt//
+------+
|s1|
+------+
|6|
|6|
|19|
+------+
3rowsinset(0.00sec)
实行历程后,传进值1,如下面例子,值19被拔出到表t中。
Question
成绩
成绩:CALLp13(NULL)//的感化是甚么?
另外一个:这个CALL语句做了那些举措?
你能够经由过程实行后察看SELECT做了甚么,也能够依据代码判别,在5秒内做出。
Answer
谜底
mysql>CALLp13(NULL)//
QueryOK,1rowaffected(0.00sec)
mysql>SELECT*FROMt//
+------+
|s1|
+------+
|6|
|6|
|19|
|19|
+------+
4rowsinset(0.00sec)
谜底是当你挪用p13时,MySQL拔出了另外一条包括数值19的纪录。缘故原由是变量variable1的值为NULL,CASE语句的ELSE部分就被实行了。但愿这对人人成心义。假如你回覆不出来,没有成绩,我们能够持续向下走。
Loops轮回语句
WHILE...ENDWHILE
LOOP...ENDLOOP
REPEAT...ENDREPEAT
GOTO
上面我们将会创立一些轮回。我们有三种尺度的轮回体例:
WHILE轮回,LOOP轮回和REPEAT轮回。另有一种非尺度的轮回体例:GOTO(译者语:最好不要用吧,用了就使流程凌乱)。
WHILE...ENDWHILE
CREATEPROCEDUREp14()
BEGIN
DECLAREvINT;
SETv=0;
WHILEv<5DO
INSERTINTOtVALUES(v);
SETv=v+1;
ENDWHILE;
END;//
这是WHILE轮回的体例。我很喜好这类体例,它跟IF语句类似,因而不必要把握良多新的语法。这里的INSERT和SET语句在WHILE和ENDWHILE之间,当变量v年夜于5的时分轮回将会加入。利用
"SETv=0;"
语句使为了避免一个罕见的毛病,假如没有初始化,默许变量值为NULL,而NULL和任何值操纵了局都为NULL。
WHILE...ENDWHILEexample
mysql>CALLp14()//
QueryOK,1rowaffected(0.00sec)
以上就是挪用历程p14的了局不必存眷体系前往是"onerowaffected"仍是"fiverowsaffected",由于这里的计数只对最初一个INSERT举措举行计数。
WHILE...ENDWHILEexample:CALL
mysql>select*fromt;//
+------+
|s1|
+------+
....
|0|
|1|
|2|
|3|
|4|
+------+
9rowsinset(0.00sec)
挪用后能够看到程序向数据库中拔出了5行。
REPEAT...ENDREPEAT
CREATEPROCEDUREp15()
BEGIN
DECLAREvINT;
SETv=0;
REPEAT
INSERTINTOtVALUES(v);
SETv=v+1;
UNTILv>=5
ENDREPEAT;
END;//
这是一个REPEAT轮回的例子,功效和后面WHILE轮回一样。区分在于它在实行后反省了局,而WHILE则是实行前反省。(译者语:大概同等于DOWHILE吧)
REPEAT...ENDREPEAT:lookattheUNTIL:UNTIL的感化
CREATEPROCEDUREp15()
BEGIN
DECLAREvINT;
SETv=0;
REPEAT
INSERTINTOtVALUES(v);
SETv=v+1;
UNTILv>=5<--
ENDREPEAT;
END;//
注重到UNTIL语句前面没有分号,在这里能够不写分号,固然你加上分外的分号更好。
REPEAT...ENDREPEAT:calling:挪用
mysql>CALLp15()//
QueryOK,1rowaffected(0.00sec)
mysql>SELECTCOUNT(*)FROMt//
+----------+
|COUNT(*)|
+----------+
|14|
+----------+
1rowinset(0.00sec)
我们能够看到挪用p15历程后又拔出了5行纪录
LOOP...ENDLOOP
CREATEPROCEDUREp16()
BEGIN
DECLAREvINT;
SETv=0;
loop_label:LOOP
INSERTINTOtVALUES(v);
SETv=v+1;
IFv>=5THEN
LEAVEloop_label;
ENDIF;
ENDLOOP;
END;//
以上是LOOP轮回的例子。
LOOP轮回不必要初始前提,这点和WHILE轮回类似,同时它又和REPEAT轮回一样也不必要停止前提。
LOOP...ENDLOOP:withIFandLEAVE包括IF和LEAVE的LOOP轮回
CREATEPROCEDUREp16()
BEGIN
DECLAREvINT;
SETv=0;
loop_label:LOOP
INSERTINTOtVALUES(v);
SETv=v+1;
IFv>=5THEN<--
LEAVEloop_label;
ENDIF;
ENDLOOP;
END;//
在轮回外部到场IF语句,在IF语句中包括LEAVE语句。这里LEAVE语句的意义是分开轮回。
LEAVE的语法是LEAVE加轮回语句标号,关于轮回语句的标号成绩我会在前面进一步解说。
LOOP...ENDLOOP:calling:挪用
mysql>CALLp16()//
QueryOK,1rowaffected(0.00sec)
mysql>SELECTCOUNT(*)FROMt//
+----------+
|COUNT(*)|
+----------+
|19|
+----------+
1rowinset(0.00sec)
挪用历程p16后,了局是另5行被拔出表t中。
Labels标号
CREATEPROCEDUREp17()
label_1:BEGIN
label_2:WHILE0=1DOLEAVElabel_2;END
WHILE;
label_3:REPEATLEAVElabel_3;UNTIL0=0
ENDREPEAT;
label_4:LOOPLEAVElabel_4;ENDLOOP;
END;//
最初一个轮回例子中我利用了语句标号。如今这里有一个包括4个语句标号的历程的例子。我们能够在BEGIN、WHILE、REPEAT大概LOOP语句前利用语句标号,语句标号只能在正当的语句后面利用。因而"LEAVElabel_3"意味着分开语句标号名界说为label_3的语句或复合语句。
EndLabels标号停止符
CREATEPROCEDUREp18()
label_1:BEGIN
label_2:WHILE0=1DOLEAVElabel_2;END
WHILElabel_2;
label_3:REPEATLEAVElabel_3;UNTIL0=0
ENDREPEATlabel_3;
label_4:LOOPLEAVElabel_4;ENDLOOP
label_4;
ENDlabel_1;//
你也能够在语句停止时利用语句标号,和在开首时利用一样。这些标号停止符并非非常有效。
它们是可选的。假如你必要,他们必需和入手下手界说的标号名字一样固然为了有优秀的编程习气,便利别人浏览,最好仍是利用标号停止符。
LEAVEandLabels跳出和标号
CREATEPROCEDUREp19(parameter1CHAR)
label_1:BEGIN
label_2:BEGIN
label_3:BEGIN
IFparameter1ISNOTNULLTHEN
IFparameter1=aTHEN
LEAVElabel_1;
ELSEBEGIN
IFparameter1=bTHEN
LEAVElabel_2;
ELSE
LEAVElabel_3;
ENDIF;
END;
ENDIF;
ENDIF;
END;
END;
END;//
LEAVE
语句使程序跳出庞大的复合语句。
ITERATE
迭代假如方针是ITERATE(迭代)语句的话,就必需用到LEAVE语句
CREATEPROCEDUREp20()
BEGIN
DECLAREvINT;
SETv=0;
loop_label:LOOP
IFv=3THEN
SETv=v+1;
ITERATEloop_label;
ENDIF;
INSERTINTOtVALUES(v);
SETv=v+1;
IFv>=5THEN
LEAVEloop_label;
ENDIF;
ENDLOOP;
END;//
ITERATE
(迭代)语句和LEAVE语句一样也是在轮回外部的轮回援用,它有点像C言语中的“Continue”,一样它能够呈现在复合语句中,援用复合语句标号,ITERATE(迭代)意义是从头入手下手复合语句。
那我们启动并察看上面这个轮回,这是个必要迭代历程的轮回:
ITERATE:Walkingthroughtheloop
深切轮回
CREATEPROCEDUREp20()
BEGIN
DECLAREvINT;
SETv=0;
loop_label:LOOP<--
IFv=3THEN
SETv=v+1;
ITERATEloop_label;
ENDIF;
INSERTINTOtVALUES(v);
SETv=v+1;
IFv>=5THEN
LEAVEloop_label;
ENDIF;
ENDLOOP;
END;//
让这个已界说了标号的轮回运转起来。
ITERATE:Walkingthroughtheloop
CREATEPROCEDUREp20()
BEGIN
DECLAREvINT;
SETv=0;
loop_label:LOOP
IFv=3THEN<--
SETv=v+1;
ITERATEloop_label;
ENDIF;
INSERTINTOtVALUES(v);
SETv=v+1;
IFv>=5THEN
LEAVEloop_label;
ENDIF;
ENDLOOP;
END;//
v的值酿成3,然后我们把它增添到4。
ITERATE:walkingthroughtheloop
CREATEPROCEDUREp20()
BEGIN
DECLAREvINT;
SETv=0;
loop_label:LOOP
IFv=3THEN
SETv=v+1;
ITERATEloop_label;<--
ENDIF;
INSERTINTOtVALUES(v);
SETv=v+1;
IFv>=5THEN
LEAVEloop_label;
ENDIF;
ENDLOOP;
END;//
然后入手下手ITERATE(迭代)历程。
ITERATE:walkingthroughtheloop
CREATEPROCEDUREp20()
BEGIN
DECLAREvINT;
SETv=0;
loop_label:LOOP<--
IFv=3THEN
SETv=v+1;
ITERATEloop_label;
ENDIF;
INSERTINTOtVALUES(v);
SETv=v+1;
IFv>=5THEN
LEAVEloop_label;
ENDIF;
ENDLOOP;
END;//
这里的ITERATE(迭代)让轮回又回到了轮回的头部。
ITERATE:walkingthroughtheloop
CREATEPROCEDUREp20()
BEGIN
DECLAREvINT;
SETv=0;
loop_label:LOOP
IFv=3THEN
SETv=v+1;
ITERATEloop_label;
ENDIF;
INSERTINTOtVALUES(v);
SETv=v+1;
IFv>=5THEN
LEAVEloop_label;<--
ENDIF;
ENDLOOP;
END;//
当v的值变成5时,程序将实行LEAVE语句
ITERATE:walkingthroughtheloop
CREATEPROCEDUREp20()
BEGIN
DECLAREvINT;
SETv=0;
loop_label:LOOP
IFv=3THEN
SETv=v+1;
ITERATEloop_label;
ENDIF;
INSERTINTOtVALUES(v);
SETv=v+1;
IFv>=5THEN
LEAVEloop_label;
ENDIF;
ENDLOOP;
END;//<--
LEAVE的了局就是跳出轮回,使运转指令抵达复合语句的最初一步。
GOTO
CREATEPROCEDUREp...
BEGIN
...
LABELlabel_name;
...
GOTOlabel_name;
...
END;
MySQL的存储过程当中可使用GOTO语句。固然这不是尺度SQL语句,并且在这里创建标号的办法也和常规中的纷歧样。因为为了和其他DBMS兼容,这个语句会慢被减少,以是我们在MySQL参考手册中没有说起。
Grandcombination
年夜组合
CREATEPROCEDUREp21
(INparameter_1INT,OUTparameter_2INT)
LANGUAGESQLDETERMINISTICSQLSECURITYINVOKER
BEGIN
DECLAREvINT;
labelgoto_label;start_label:LOOP
IFv=vTHENLEAVEstart_label;
ELSEITERATEstart_label;
ENDIF;
ENDLOOPstart_label;
REPEAT
WHILE1=0DOBEGINEND;
ENDWHILE;
UNTILv=vENDREPEAT;
GOTOgoto_label;
END;//
下面例子中的语句包括了我们之前讲的一切语法,包含参数列表,特征参数,BEGIN/END块复合语句,变量声明,IF,WHILE,LOOP,REPEAT,LEAVE,ITERATE,GOTO。这是一个荒唐的存储历程,我不会运转它,由于内里有没有尽的轮回。可是内里的语法却非常正当。这些是新的流程把持和变量声明语句。上面我们将要打仗更多新的器材。
未完待续...
正如前文所提到的,MySQL易学、易部署、易管理和易维护。 不过话说回来了,绝大多数的性能优化准则与对sqlserver存储的结构理解息息相关 而SQLServer如果能像Oracle一样可以为登陆分配如:5%的cpu,10%的内存。就可以解决这个漏洞。 SQLServer的异构移植功能个人感觉最好了。(如果对比过SQLServer的链接服务器和Oracle的透明网关的朋友会发现SQLServer的sp_addlinkedserver(openquery)异构数据库系列比Oracle真是强太多了。) 始终遗憾SQLServer的登陆无法分配CPU/内存占用等指标数。如果你的SQLServer给别人分配了一个只可以读几个表的权限,而这个家伙疯狂的死循环进行连接查询,会给你的系统带来很大的负担。 这是一个不错的新特性。虽然索引的附加字段没有索引键值效率高,但是相对映射到数据表中效率还是提高了很多。我做过试验,在我的实验环境中会比映射到表中提高30%左右的效率。 groupby子句可以将查询结果分组,并返回行的汇总信息Oracle按照groupby子句中指定的表达式的值分组查询结果。 对递归类的树遍历很有帮助。个人感觉这个真是太棒了!阅读清晰,非常有时代感。 where子句的作用是在对查询结果进行分组前,将不符合where条件的行去掉,即在分组之前过滤数据,条件中不能包含聚组函数,使用where条件显示特定的行。
页:
[1]