MySQL 5.0 新特征教程 存储进程:第二讲

 来源:网海拾贝  




作者:mysql AB;翻译:陈朋奕

  Why MySQL Statements are Legal in a Procedure Body
  什么MySQL语句在存储进程体中是正当的?

  什么样的SQL语句在Mysql存储进程中才是正当的呢?你可以创立一个包括INSERT, UPDATE,DELETE, SELECT, DROP, CREATE, REPLACE等的语句。你唯一需求记着的是假定代码中包括MySQL扩展成效,那么代码将不能移植。在模范模范SQL语句中:任何数据库界说说话都是正当的,如:

 

CREATE PROCEDURE p () DELETE FROM t; //
  SET、COMMIT以及ROLLBACK也是正当的,如:
CREATE PROCEDURE p () SET @x = 5; //

  MySQL的附加成效:任何数据操作说话的语句都将正当。
CREATE PROCEDURE p () DROP TABLE t; //

  MySQL扩展成效:间接的SELECT也是正当的:
CREATE PROCEDURE p () SELECT 'a'; //

  专程提一下,我将存储进程中包括DDL语句的成效称为MySQL附加成效的缘由是在SQL模范模范中把这个界说为非核心的,即可选组件。

  在进程体中有一个束缚,就是不能有对例程或表操作的数据库操作语句。例如下面的例子便是非法的:
CREATE PROCEDURE p1 ()
CREATE PROCEDURE p2 () DELETE FROM t; //

  下面这些对MySQL 5.0来说全新的语句,进程体中是非法的:
CREATE PROCEDURE, ALTER PROCEDURE, DROP PROCEDURE, CREATE FUNCTION,
DROP FUNCTION, CREATE TRIGGER, DROP TRIGGER.

  不过你可以利用
CREATE PROCEDURE db5.p1 () DROP DATABASE db5//

  然则沟通
"USE database"

  语句也是非法的,由于MySQL假定默许数据库就是进程的事情场所。

  Call the Procedure 调用存储进程
  1.
  如今我们就可以调用一个存储进程了,你所需求输出的全部就是CALL和你进程名以及一个括号再一次夸大,括号是必须确当你调用例子外面的p1进程时,成就是屏幕前往了t表的内容
mysql> CALL p1() //
------
| s1 |
------
| 5 |
------
1 row in set (0.03 sec)
Query OK, 0 rows affected (0.03 sec)

  由于进程中的语句是
"SELECT * FROM t;"

  2. Let me say that again, another way.
  其他完成体例
mysql> CALL p1() //

  和下面语句的执行成就一样:
mysql> SELECT * FROM t; //

  以是,你调用p1进程就相称于你执行了下面语句:
"SELECT * FROM t;"

  好了,垂危的常识点"创立和调用进程办法"已经明白了。我进展你能对自身说这相称朴实。然则很快我们就有一系列的训练,每次都加一条子句,大体改动已经存在的子句。那样在写庞大部件前我们将会有良多可用的子句。

Characteristics Clauses 特征子句
  1.
CREATE PROCEDURE p2 ()
LANGUAGE SQL <--
NOT DETERMINISTIC <--
SQL SECURITY DEFINER <--
COMMENT 'A Procedure' <--
SELECT CURRENT_DATE, RAND() FROM t //

  这里我给出的是一些能反响存储进程特征的子句。子句内容在括号之后,主体之前。这些子句都是可选的,他们有什么感化呢?

  2.
CREATE PROCEDURE p2 ()
LANGUAGE SQL <--
NOT DETERMINISTIC
SQL SECURITY DEFINER
COMMENT 'A Procedure'
SELECT CURRENT_DATE, RAND() FROM t //

  很好,这个LANGUAGE SQL子句是没有感化的。仅是为了剖析');下面进程的主体利用SQL说话编写。这条是系统默许的,但你在这里声明是有效的,由于某些DBMS(IBM的DB2)需求它,假定你关注DB2的兼容成就最好还是用上。此外,当前大体味呈现除SQL外的其他说话撑持的存储进程。

  3.
CREATE PROCEDURE p2 ()
LANGUAGE SQL
NOT DETERMINISTIC <--
SQL SECURITY DEFINER
COMMENT 'A Procedure'
SELECT CURRENT_DATE, RAND() FROM t //

  下一个子句,NOT DETERMINISTIC,是传递给系统的信息。这里一个确定进程的界说就是那些每次输出一样输出也一样的挨次。在这个案例中,既然主体中含有SELECT语句,那前往肯定是未知的因而我们称其NOT DETERMINISTIC。然则MySQL内置的优化挨次不会细心这个,至少在如今不细心。

  4.
CREATE PROCEDURE p2 ()
LANGUAGE SQL
NOT DETERMINISTIC
SQL SECURITY DEFINER <--
COMMENT 'A Procedure'
SELECT CURRENT_DATE, RAND() FROM t //
  下一个子句是SQL SECURITY,可以界说为SQL SECURITY DEFINER或SQL SECURITY INVOKER。
  这就进入了权限控制的领域了,固然我们在前面将会有测试权限的例子。
SQL SECURITY DEFINER

  意味着在调用时搜索创立进程用户的权限(另一个选项是SQLSECURITY INVOKER)。
  如今而言,利用
SQL SECURITY DEFINER

  指令通知MySQL效劳器搜索创立进程的用户就可以了,当进程已经被调用,就不搜索执行调用进程的用户了。而另一个选项(INVOKER)则是通知效劳器在这一步仍然要搜索调用者的权限。

  5.
CREATE PROCEDURE p2 ()
LANGUAGE SQL
NOT DETERMINISTIC
SQL SECURITY DEFINER
COMMENT 'A Procedure' <--
SELECT CURRENT_DATE, RAND() FROM t //

  COMMENT 'A procedure'
  是一个可选的正文剖析');。

  最初,正文子句会跟进程界说存储在一同。这个没有巩固的模范模范,我在文中会指出没有巩固模范模范的语句,不过侥幸的是这些在我们模范模范的SQL中很少。

  6.
CREATE PROCEDURE p2 ()
LANGUAGE SQL
NOT DETERMINISTIC
SQL SECURITY DEFINER
COMMENT ''
SELECT CURRENT_DATE, RAND() FROM t //

  下面进程跟下面语句是等效的:
CREATE PROCEDURE p2 ()
SELECT CURRENT_DATE, RAND() FROM t //

  特征子句也有默许值,假定省略了就相称于:
LANGUAGE SQL NOT DETERMINISTIC SQL SECURITY DEFINER COMMENT ''

Digressions一些题外话

  Digression:
  调用p2()//的成就
mysql> call p2() //
-------------- -----------------
| CURRENT_DATE | RAND() |
-------------- -----------------
| 2004-11-09 | 0.7822275075896 |
-------------- -----------------
1 row in set (0.26 sec)
Query OK, 0 rows affected (0.26 sec)
  当调用进程p2时,一个SELECT语句被执行前往我们希冀获得的随机数。
  Digression: sql_mode unchanging
  不会改动的

sql_mode
mysql> set sql_mode='ansi' //
mysql> create procedure p3()select'a'||'b'//
mysql> set sql_mode=''//
mysql> call p3()//
------------
| 'a' || 'b' |
------------
| ab |
------------

  MySQL在进程创立时会主动坚持运转情况。例如:我们需求利用两条竖线来跟尾字符串然则这只需在sql mode为ansi的时候才正当。假定我们将sql mode改为non-ansi,不必担心,它仍然能事情,只需它第一次利用时能正常事情。

Exercise 训练

  Question
  成就
  假定你不介意训练一下的话,试能否不看前面的谜底就能处理赏罚这些哀求。
  创立一个进程,暗示`Hello world`。用大约5秒时候去思虑这个成就,既然你已经学到了这里,这个应该很朴实。当你思虑成就的时候,我们再随机选择一些刚刚讲过的工具温习:
  DETERMINISTIC
  (确定性)子句是反响输出和输出寄予特征的子句…调用进程利用CALL进程名(参数列表)体例。好了,我猜时候也到了。

  Answer
  谜底
  好的,谜底就是在进程体中包括
"SELECT 'Hello, world'"
  语句
  MySQL
mysql> CREATE PROCEDURE p4 () SELECT 'Hello, world' //
Query OK, 0 rows affected (0.00 sec)
mysql> CALL p4()//
--------------
| Hello, world |
--------------
| Hello, world |
--------------
1 row in set (0.00 sec)
Query OK, 0 rows affected (0.00 sec)

Parameters 参数

  让我们更进一步的研讨怎样在存储进程中界说参数
  1. CREATE PROCEDURE p5
  () ...
  2. CREATE PROCEDURE p5
  ([IN] name data-type) ...
  3. CREATE PROCEDURE p5
  (OUT name data-type) ...
  4. CREATE PROCEDURE p5
  (INOUT name data-type) ...

  回忆一下前面讲过的参数列表必须在存储进程名后的括号中。下面的第一个例子中的参数列表是空的,第二个例子中有一个输出参数。这里的词IN可选,由于默许参数为IN(input)。

  第三个例子中有一个输出参数,第四个例子中有一个参数,既能作为输出也可以作为输出。
  IN example 输出的例子
mysql> CREATE PROCEDURE p5(p INT) SET @x = p //
Query OK, 0 rows affected (0.00 sec)
mysql> CALL p5(12345)//
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT @x//
-------
| @x |
-------
| 12345 |
-------
1 row in set (0.00 sec)

  这个IN的例子演示的是有输出参数的进程。在进程体中我将会话变量x设定为参数p的值。然后调用进程,将12345传入参数p。选择暗示会话变量@x,证实我们已经将参数值12345传入。
  OUT example 输出的例子
mysql> CREATE PROCEDURE p6 (OUT p INT)
-> SET p = -5 //
mysql> CALL p6(@y)//
mysql> SELECT @y//
------
| @y |
------
| -5 |
------

  这是另一个例子。此次的p是输出参数,然后在进程调用中将p的值传入会话变量@y中。

  在进程体中,我们给参数赋值-5,在调用后我们可以看出,OUT是通知DBMS值是从进程中传出的。
  异常我们可以用语句
"SET @y = -5;"

  来到达异常的成就

Compound Statements 复合语句

  如今我们睁开的注重剖析一下进程体:
CREATE PROCEDURE p7 ()
BEGIN
SET @a = 5;
SET @b = 5;
INSERT INTO t VALUES (@a);
SELECT s1 * @a FROM t WHERE s1 >= @b;
END; // /* I won't CALL this.
这个语句将不会被调用
*/

  完成进程体的布局就是BEGIN/END块。这个BEGIN/END语句块和Pascal说话中的BEGIN/END是根内情同的,和C说话的框架是很沟通的。我们可以利用块去封装多条语句。在这个例子中,我们利用了多条设定会话变量的语句,然后完成了一些insert和select语句。假定你的进程体中有多条语句,那么你就需求BEGIN/END块了。BEGIN/END块也被称为复合语句,在这里你可以终了变量界说和流程控制。




版权声明: 原创作品,容许转载,转载时请务必以超链接方法标明文章 原始起因 、作者信息和本声明。否则将究查法律责任。

原文地址:https://www.cnblogs.com/zgqjymx/p/1975701.html