文章目录
- 工具准备
- 第十九章 - 插入数据
- 数据插入
- 插入完整的行
- 插入多个行
- 插入检索出的数据
- 第二十章 - 更新和删除数据
- 更新数据
- 删除数据
- 更新和删除原则
- 第二十一章 - 创建和操纵表
- 创建表
- 表创建基础
- 使用 NULL 值
- 主键
- 指定默认值
- 引擎类型
- 更新表
- 删除表
- 重命名表
- 第二十二章 - 使用视图
- 为什么使用视图
- 视图的规则和限制
- 使用视图
- 利用视图简化复杂的联结
- 用视图重新格式化检索出的数据
- 用视图过滤不想要的数据
- 使用视图与计算字段
- 更新视图
- 第二十三章 使用存储过程
- 为什么要使用存储过程
- 执行存储过程
- 创建存储过程
- 删除存储过程
- 使用参数
- 建立智能存储过程
- 检查存储过程
工具准备
MySQL Workbench 8.0
create schema crashcourse;
use crashcourse;
分别运行 create.sql 和 populate.sql
这两个脚本下载地址:
第十九章 - 插入数据
数据插入
INSERT
用来插入( 或添加 )行到数据库表地。插入可以用以下几种方式使用:
- 插入完整的行
- 插入行的一部分
- 插入多行
- 插入某些查询的结果
插入完整的行
INSERT INTO customers
VALUES(NULL,
'Pep E, LaPew',
'100 Main Street',
'Los Angeles',
'CA',
'90046',
'USA',
NULL,
NULL
);
如果插入的数据某列没有值,应该使用 NULL
值。第一列的 cust_id
也为 NULL
是因为每次插入一个新行时,该列由 MySQL
自动增量。
此种语法简单,但不安全,应该避免使用。上面的语句高度依赖于表中列的定义次序,并且含依赖于其次序容易获得的信息。即使可得到这种次序信息,也不能保证下一次表结构变动后各个列保持完全相同的次序。
更安全的方法如下:
INSERT INTO customers(cust_name,
cust_address,
cust_city,
cust_state,
cust_zip,
cust_country,
cust_contact,
cust_email)
VALUES('Pep E. LaPew',
'100 Main Street',
'Los Angeles',
'CA',
'90046',
'USA',
NULL,
NULL
);
省略列 如果表的定义允许,则可以在
INSERT
操作中省略某些列。省略的咧必须满足以下某个条件
- 该列定义为允许 NULL 值
- 该表定义中给出默认值。这表示如果不给值,将使用默认值
如果表中不允许 NULL 值且没有默认值的列不给出值,则
MySQL
将产生一条错误消息,并且相应的行插入不成功
插入多个行
INSERT INTO customers(cust_name,
cust_address,
cust_city,
cust_state,
cust_zip,
cust_country)
VALUES('Pep E. LaPew',
'100 Main Street',
'Los Angeles',
'CA',
'90046',
'USA');
INSERT INTO customers(cust_name,
cust_address,
cust_city,
cust_state,
cust_zip,
cust_country)
VALUES('M. Martian',
'42 Galaxy Way',
'New York',
'NY',
'11213',
'USA');
或者,只要每条 INSERT
语句中的列名( 和次序 )相同,可以如下组合:
INSERT INTO customers(cust_name,
cust_address,
cust_city,
cust_state,
cust_zip,
cust_country)
VALUES('Pep E. LaPew',
'100 Main Street',
'Los Angeles',
'CA',
'90046',
'USA'),
('M. Martian',
'42 Galaxy Way',
'New York',
'NY',
'11213',
'USA');
插入检索出的数据
INSERT
一般用来给表插入一个指定列值的行。但是,INSERT
还存在另一种形式,可以利用它将一条 SELECT
语句的结果插入表中。即 INSERT SELECT
。
假如想从另一表中合并客户列表到你的 customers
表。
首先创建和填充
custnew
表,在填充custnew
时,不应使用已经在customers
中使用过的cust_id
值( 如果主键值重复,后续的INSERT
操作将会失败 )或仅省略这列值让MySQL
在导入的过程中产生新值
INSERT INTO customers(cust_id,
cust_contact,
cust_email,
cust_name,
cust_address,
cust_city,
cust_state,
cust_zip,
cust_country)
SELECT cust_id,
cust_contact,
cust_email,
cust_name,
cust_address,
cust_city,
cust_state,
cust_zip,
cust_country
FROM custnew;
INSERT SELECT中的列名 实际上,不一定要求列明匹配。事实上,
MySQL
甚至不关心SELECT
返回的列名。它使用的是列的为止,因此SELECT
中的第一列( 不管其列名 )将用来填充表列中的第一个列,以此类推。这对于从使用不同列名的表中导入数据是非常有用的
INSERT SELECT
中的 SELECT
语句可包含 WHERE
子句以过滤插入的数据
第二十章 - 更新和删除数据
更新数据
为了更新表中数据,可使用 UPDATE
语句。可采用两种方式使用 UPDATE
:
- 更新表中特定行
- 更新表中所有行
不要省略WHERE子句 在使用 UPDATE 时一定要注意细心。因为稍不注意,今后会回更新表中所有行。
UPDATE与安全 可以限制和控制
UPDATE
语句的使用
基本的的 UPDATE
语句由 3 部分组成
- 要更新的表
- 列名和它们的新值
- 确定要更新行的过滤条件
举例:客户 10005 现在有了电子邮件地址,因此他的记录需要更新:
UPDATE customers
SET cust_email = 'elmer@fudd.com'
WHERE cust_id = 10005;
UPDATE
语句总是以要更新的表的名字开始。在此例中,要更新的表的名字为 customers
。SET
子句设置 cust_email
列为指定的值:
SET cust_email = 'elmer@fudd.com'
UPDATE
语句以 WHERE
子句结束,它告诉 MySQL
更新哪一行。没有 WHERE
子句,将会用这个电子邮件地址更新 customers
表中所有的行
更新多个列:
UPDATE customers
SET cust_name = 'The Fudds',
cust_email = 'elmer@fudd.com'
WHERE cust_id = 10005;
在更新多个列时,只需要使用单个 SET
命令,每个 “列=值” 对之间用逗号分隔。在此例中,更新客户 10005 的 cust_name
和 cust_email
列
在 UPDATE 语句中使用子查询
UPDATE
语句中可以使用子查询,使得能用SELECT
语句检索出的语句更新列数据IGNORE 关键字 如果用
UPDATE
居于更新多行,并且在更新这些行中的一行或多行时出现一个错误,则整个UPDATE
操作被取消(错误发生前更新的所有行被恢复到它们原来的值)。为即使时发生错误,也继续进行更新,可使用IGNORE
关键字UPDATE IGNORE customers...
为了删除某个列的值,可设置为 NULL
UPDATE customers
SET cust_email = NULL
WHERE cust_id = 10005;
删除数据
为了从一个表中删除数据,使用 DELETE
语句。
- 从表中删除特定的行
- 从表中删除所有行
不要省略WHERE子句 在使用
DELETE
时一定要注意细心。因为稍不注意,今后会回更新表中所有行。
DELETE FROM customers
WHERE cust_id = 10006;
删除表的内容而不是表
DELETE
语句从表中删除行,甚至时删除表中所有行,但,DELETE
不删除表本身更快的删除 如果向从表中删除所有行,不要使用
DELETE
可使用TRUNCATE TABLE
语句,它完成相同的工作。但速度更快(TRUNCATE
实际是删除原来的表并重新创建一个表,而不是逐行删除表中的数据 )。
更新和删除原则
- 除非确实打算更新和删除每一行,否则绝对不要使用不带
WHERE
子句的UPDATE
或DELETE
语句 - 保证每个表都有主键,尽可能像
WHERE
子句那样使用它( 可以指定各主键、多个值或值的范围 )。 - 在对
UPDATE
或DELETE
语句使用WHERE
子句前,应该先用SELECT
进行测试,保证它过滤的是正确的记录,以防编写的WHERE
子句不正确。 - 使用强制实施引用完整性的数据库,这样
MySQL
将不会允许删除具有与其他表相关联的数据的行
第二十一章 - 创建和操纵表
创建表
除了软件,用程序创建表,可使用 SQL
的 CREATE TABLE
语句。
表创建基础
为利用 CREATE TABLE
创建表,必须给出下列信息:
- 新表的名字,在关键字
CREATE TABLE
之后给出 - 表列的名字和定义,用逗号分隔
CREATE TABLE
语句也可能会包括其他关键字或选项,但至少要包括表的名字和列的细节。
CREATE TABLE customers
(
cust_id int NOT NULL AUT_INCREMENT,
cust_name char(50) NOT NULL,
cust_address char(50) NULL,
cust_city char(50) NULL,
csut_state char(5) NULL,
cust_zip char(10) NULL,
cust_country char(50) NULL,
cust_contact char(50) NULL,
cust_email char(255) NULL,
PRIMARY KEY (cust_id)
) ENGINE=InnoDB;
实际的表定义( 所有列 )括在圆括号之中。各列之间用逗号分隔。这个表由 9 列组成。每列的定义以列名( 它在表中必须是唯一的 )开始,后跟列的数据类型。表的主键可以在创建表时用 PRIMARY KEY
关键字指定。
使用 NULL 值
每个表列或者是 NULL
值,或者是 NOT NULL
列,这种状态在创建时由表的定义规定
CREATE TABLE orders
(
order_num int NOT NULL AUTO_INCREMENT,
order_date datetime NOT NULL,
cust_id int NOT NULL,
PRIMARY KEY(order_num)
) ENGINE=InnoDB;
主键
主键值必须唯一。即,表中的每个行必须具有唯一的主键值。如果主键使用单个列,则它的值必须唯一。如果使用多个列,则这些列的组合值必须唯一
CREATE TABLE orderitems
(
order_num int NOT NULL,
order_item int NOT NULL,
prod_id char(10) NOT NULL,
quantity int NOT NULL,
item_price decimal(8,2) NOT NULL,
PRIMARY KEY(order_num, order_item)
) ENGINE=InnoDB;
orderitems
表包含 orders
表中每个订单的细节。每个订单有多项物品,但每个订单任何时候都只有 1 个第一项物品,1 个第二项物品,如此等等。因此,订单号( order_num
列 )和订单物品( order_item
列 )的组合是唯一的,从而适合作为主键。
指定默认值
如果在插入行时没有给出之,MySQL
允许指定此时使用的默认值。默认值用 CREATE TABLE
语句的列定义中的 DEFAULT
关键字指定。
CREATE TABLE orderitems
(
order_num int NOT NULL,
order_item char(10) NOT NULL,
quantity int NOT NULL DEFAULT 1,
item_price decimal(8, 2) NOT NULL,
PRIMARY KEY(order_num, order_item)
) ENGINE=InnoDB;
这条语句创建包含组成订单的各物品的 orderitems
表(订单本身存储在 orders
表中)。quantity
列包含订单中每项物品的数量。在此例中,给该列的描述添加文本 DEFAULT
指示在未给出数量的情况下使用数量 1.
引擎类型
与其他 DBMS
一样,MySQL
有一个具体管理和处理数据的内部引擎。在使用 CREATE TABLE
语句时,该引擎具体创建表,而在使用 SELECT
语句或进行其他数据库处理时,该引擎在内部处理请求。MySQL
与其他 DBMS
不一样,它具有多种引擎。它打包多个引擎,这也引擎都隐藏在服务器内,全都能执行 CREATE TABLE
和 SELECT
等命令
几个需要知道的引擎:
-
InnoDB
是一个可靠的事务处理引擎(26章) -
MEMORY
在功能等同于MyISAM
, 但由于数据存储在内存中,速度很快(适合临时表) -
MyISAM
是一个性能极高的引擎,支持全文本搜索,但不支持事务处理
更新表
为更新表定义,可使用 ALTER TABLE
语句。但是,理想状态下,当表中存储数据以后,该表就不应该被更新。
为了使用 ALTER TABLE
更改表结构,必须给出下面的信息:
- 在
ALTER TABLE
之后给出要更改的表明(该表必须存在,否则将出错) - 所做更改的列表
添加列
ALTER TABLE vendors
ADD vend_phone CHAR(20);
注意:必须明确数据类型
删除刚才添加的列
ALTER TABLE vendors
DROP COLUMN vend_phone;
ALTER TABLE
的一种常见用途是定义外键。下面是用来定义本书中的表所用的外键的代码:
ALTER TABLE orderitems
ADD CONSTRAINT fk_orderitems_orders
FOREIGN KEY (order_num) REFERENCES orders (order_num);
ALTER TABLE orderitems
ADD CONSTRAINT fk_orderitems_products FOREIGN KEY (prod_id)
REFERENCES products (prod_id);
ALTER TABLE orders
ADD CONSTRAINT fk_orders_customers FOREIGN KEY (cust_id);
REFERENCES customers (cust_id);
ALTER TABLE products
ADD CONSTRAINT fk_products_vendors
FOREIGN KEY (vend_id) REFERENCES vendors (vend_id);
这里,更改了 4 个不同的表。为了对单个表进行多个更改,可以使用单条 ALTER TABLE
语句,每个更改用逗号分隔
复杂的表结构更改一般需要手动删除过程,涉及以下步骤
- 用新的列布局创建一个新表
- 使用
INSERT SELECT
语句从旧表复制数据到新表。如果有必要,可使用转换函数和计算字段 - 检验包含所需数据的新表
- 重命名旧表(如果确定,可以删除)
- 用旧表原来的名字重命名新表
- 根据需要,重新创建触发器、存储过程、索引和外键
删除表
DROP TABLE
DROP TABLE customers2;
重命名表
RENAME TABLE customers2 TO customers;
可以使用下面的语句对多个表重命名:
RENAME TABLE backup_customers TO customers,
backup_vendors TO vendors,
backup_products TO products;
第二十二章 - 使用视图
视图时虚拟的表。与包含数据的表不一样,视图只包含使用时动态检索数据的查询
第十五章中用 SELECT
从三个表中检索数据的例子
SELECT cust_name, cust_contact
FROM customers, orders, orderitems
WHERE customers.cust_id = orders.cust_id
AND orderitems.order_num = orders.order_num
AND prod_id = 'TNT2';
此查询用来检索订购了某个特定产品的客户。任何需要这个数据的人都必须理解相关表结构,并且知道如何创建查询和对表进行联结。为了检索其他产品(或多个产品)的相同数据,必须修改最后的 WHERE
子句
现,假如可以把整个查询包装成一个名为 productcustomers
的虚拟表,则可以如下轻松地检索出相同的数据
SELECT cust_name, cust_contact
FROM productcustomers
WHERE prod_id = 'TNT2';
productcustomers
是一个视图,作为视图,它不包含表中应该有的任何列或数据,它包含的是一个 SQL
查询(我理解成接口)
为什么使用视图
视图常见应用
- 重用
SQL
语句 - 简化复杂的
SQL
操作。在编写查询后,可以方便地重用它而不必知道它的基本查询细节 - 使用表的组成部分而不是整个表
- 保护数据。可以给用户授予表的特定部分的访问权限而不是整个表的访问权限
- 更改数据格式和表示。视图可返回与底层表的表示和格式不同的数据
性能问题 因为视图不包含数据,所以每次使用视图时,都必须处理查询执行时所需的任一个检索。。如果用多个联结和过滤创建了复杂的视图或者嵌套了视图,可能会发现性能下降地厉害。
视图的规则和限制
- 与表一样,视图必须唯一命名
- 对于可以创建的视图数目没有限制
- 为了创建视图,必须具有足够的访问权限。这些限制通常由数据库管理人员授予
- 视图可以嵌套,即可以利用从其他视图中检索数据的查询来构造一个视图
-
ORDER BY
可以用在视图中,但如果从该视图检索数据SELECT
中也包含ORDER BY
,那么该视图中的ORDER BY
将被覆盖 - 视图不能索引,也不能有管理的触发器或默认值
- 视图可以和表一起使用
使用视图
视图的创建
- 视图用
CREATE VIEW
居于来创建 - 使用
SHOW CREATE VIEW viewname;
来查看创建视图的语句 - 用
DROP
删除视图,语法:DROP VIEW viewname;
- 更新视图时,也可先用
DROP
再用CREATE
,也可以直接用CREATE OR REPLACE VIEW
。如果要更新的视图不存在,则第 2 条更新语句会创建一个视图,如果更新的视图存在,则替换
利用视图简化复杂的联结
CREATE VIEW productcustomers AS
SELECT cust_name, cust_contact, prod_id
FROM customers, orders, orderitems
WHERE customers.cust_id = orders.cust_id
AND orderitems.order_num = orders.order_num;
这条语句创建一个名为 productcustomers
的视图,联结三个表,以返回已订购了任意产品的所有客户的列表。如果执行 SELECT * FROM productcustomers
,将列出订购了任意产品的客户
SELECT cust_name, cust_contact
FROM productcustomers
WHERE prod_id = 'TNT2';
用视图重新格式化检索出的数据
视图的另一个常见用途时重新格式化检索出的数据
SELECT concat(RTrim(vend_name), ' (', RTrim(vend_country), ')')
AS vend_title
FROM vendors
ORDER BY vend_name;
现,假如经常需要这个格式的结果。不必在每次需要时进行联结,创建一个视图,每次需要时使用它即可。
CREATE VIEW vendorlocations AS
SELECT concat(RTrim(vend_name), ' (', RTrim(vend_country), ')')
AS vend_title
FROM vendors
ORDER BY vend_name;
SELECT *
FROM vendorlocations;
用视图过滤不想要的数据
可以定义 customeremaillist
视图,它过滤没有电子邮件地址的客户。
CREATE VIEW customeremaillist AS
SELECT cust_id, cust_name, cust_email
FROM customers
WHERE cust_email IS NOT NULL;
SELECT *
FROM customeremaillist;
使用视图与计算字段
CREATE VIEW orderitemsexpanded AS
SELECT order_num,
prod_id,
quantity,
item_price,
quantity * item_price AS expanded_price
FROM orderitems;
SELECT *
FROM orderitemsexpanded
WHERE order_num = 20005;
更新视图
视图的数据能否更新?视情况而定
通常,视图时可更新的(即,可以对它们使用 INSERT、UPDATE 和 DELETE
)。更新一个视图将更新其基表。如果对视图增加或删除行,实际上是对其基表增加或删除行
但是并非所有视图都是可更新的。基本上,如果 MySQL
不能正确地确定被更新地基数据,则不允许更新(包括插入和删除)。这实际上意味着,如果视图定义中有以下操作,则不能进行视图的更新
- 分组( 使用
GROUP BY
和HAVING
) - 联结
- 子查询
- 并
- 聚集函数(
Min()、Count()、Sum()
等 ) DISTINCT
- 导出(计算)列
第二十三章 使用存储过程
现实情况,经常会有一个完整的操作需要多条语句才能完成。考虑以下情形:
- 为了处理订单,需要保证库存中有相应的物品
- 如果库存有物品,这些物品需要预定以便不将它们再卖给别的人,并且要减少可用的物品以反映正确的库存量
- 库存中没有的物品需要订购,这需要与供应商进行某种交互
- 关于哪些物品入库( 并且可以理解发货 )和哪些物品推定,需要通知相应的客户
如何编写语句diamagnetic?大可以单独编写每条语句,并根据结果有条件地执行另外的语句。在每次需要这个处理时( 以及每个需要它的应用中 )都必须做这些工作
可以创建存储过程。存储过程简单来说,就是为以后的使用而保存的一条或多条 MySQL
语句的集合,虽然作用不仅限于批处理
为什么要使用存储过程
- 通过把处理封装在容易使用的单元中
- 由于不要求反复建立一系列处理步骤,这保证了数据的完整性。如果所有开发人员和应用程序都是用同一( 实验和测试 )存储过程,则所使用的代码都是相同的。这一点的延伸就是防止错误。需要执行的步骤越多,出错的可能性就越大。防止错误保证了数据的一致性
- 简化对变动的管理。如果表名、列名或业务逻辑或别的内容有变化,只需要更改存储过程的代码。
这一点的眼神就是安全性。通过存储过程限制对基础数据的访问减少了数据讹误(无意识的或别的原因所导致的数据讹误)的机会
- 提高性能。因为使用存储过程比使用单独的
SQL
语句要快 - 存在一些只能用在单个请求中的
MySQL
元素和特性,存储过程可以使用它们来编写功能更强更灵活的代码
使用存储过程有 3 个主要好处,即简单、安全、高性能。
- 一般来说,存储过程的编写比基本
SQL
语句复杂,编写存储过程需要更高的技能,更丰富的经验
执行存储过程
MySQL
成存储过程的执行为调用,因此 MySQL
执行存储过程的语句为 CALL
。
CALL productpricing(@pricelow,
@pricehigh,
@priceaverage);
其中,执行名为 productpricing
的存储过程,它计算并返回产品的最低、最高和平均价格
创建存储过程
”DELIMITER //“ 表示设置“//”符号为结束语,因为mysql中默认语句结束为分号‘;’,为了避免存储过程与mysql语句符号冲突,所以有时使用DELIMITER来改变结束语符号,要配合end //来使用;
DELIMITER //
CREATE PROCEDURE productpricing()
BEGIN
SELECT Avg(prod_price) AS priceaverage
FROM products;
END//
调用:
CALL productpricing();
删除存储过程
DROP PROCEDURE productpricing;
使用参数
productpricing
只是一个简单的存储过程,它简单地显示 SELECT
语句地结果。一般,存储过程并不显示结果,而是把结果返回给你指定的变量
变量( variable ) 内存中一个特定的位置,用来临时存储数据
DELIMITER //
CREATE PROCEDURE productpricing(
OUT pl DECIMAL(8, 2),
OUT ph DECIMAL(8, 2),
OUT pa DECIMAL(8, 2)
)
BEGIN
SELECT Min(prod_price)
INTO pl
FROM products;
SELECT Max(prod_price)
INTO ph
FROM products;
SELECT Avg(prod_price)
INTO pa
FROM products;
END //
此存储过程接受 3 个参数:pl
存储产品最低价格, ph
存储最高价格,pa
存储品骏价格。每个参数必须具有指定的类型,这里时十进制。关键字 OUT
指出相应的参数用来从存储过程传出一个值(返回给调用者)。MySQL
支持 IN
( 传递给存储过程 )、OUT
( 从存储过程传出 )和 INOUT
( 对存储过程传入和传出 )类型的参数
调用:
CALL productpricing(@pricelow,
@pricehigh,
@priceaverage);
此存储过程传递 3 个参数。
变量名 所有
MySQL
变量都必须以 @ 开始
这条语句不显示任何语句,为了显示检索出的产品平均价格:SELECT @priceaverage;
获得 3 个值
SELECT @pricehigh, @pricelow, @priceaverage;
参数 IN
和 OUT
。ordertotal
接受订单号并返回改订单的合计:
DELIMITER //
CREATE PROCEDURE ordertotal(
IN onumber INT,
OUT ototal DECIMAL(8, 2)
)
BEGIN
SELECT Sum(item_price * quantity)
FROM orderitems
WHERE order_num = onumber
INTO ototal;
END //
DELIMITER ;
调用
CALL ordertotal(20005, @total);
必须给 ordertotal
传递两个参数;第一个参数为订单号,第二个参数为包含计算出来的合计的变量名
显示:SELECT @total;
建立智能存储过程
考虑场景:需要获得与以前一样的订单合计,但需要对合计增加营业税,不过只针对某些顾客。那么:
- 获得合计
- 把营业税有条件地添加到合计
- 返回合计( 带或不带税 )
DELIMITER //
-- Name: ordertotal
-- Parameters: onumber = order number
-- : taxable = 0 if not taxable, 1 if taxable
-- : ototal = order total variable
CREATE PROCEDURE ordertotal(
IN onumber INT,
IN taxable BOOLEAN,
OUT ototal DECIMAL(8, 2)
) COMMENT 'Obtain order total, optionally adding tax'
BEGIN
-- Declare variable for total
DECLARE total DECIMAL(8, 2);
-- Declare tax perentage
DECLARE taxrate INT DEFAULT 6;
-- Get the order total
SELECT Sum(item_price * quantity)
FROM orderitems
WHERE order_num = onumber
INTO total;
-- Is this taxable ?
IF taxable THEN
-- Yes, so add taxrate to the total
SELECT total + (total / 100 * taxrate) INTO total;
END IF;
-- And finally, save to out variable
SELECT total INTO ototal;
END //
DELIMITER ;
此存储过程添加了另一个参数 taxable
,它是一个布尔值,用 DECLARE
语句定义了两个局部变量。DECLARE
要求指定变量名和数据类型,它也支持可选地默认值( 这个例子中的 taxrate
的默认被设置为 6% ).SELECT
语句已经改变,因此其存储结果到 total
而不是 ototal
。
COMMENT关键字 本例中,不是必需的,但如果给出,将在
SHOW PROCEDURE STATUS
的结果中显示
CALL ordertotal(20005, 0, @total);
SELECT @total;
CALL ordertotal(20005, 1, @total);
SELECT @total;
检查存储过程
为显示用来创建一个存储过程的 CREATE
语句,使用 SHOW CREATE PROCEDURE
语句
SHOW CREATE PROCEDURE ordertotal;
为了获得包括何时、由谁创建等相信信息的存储过程列表,使用 SHOW PROCEDURE STATUS
限制过程状态结果 SHOW PROCEDURE STATUS 列出所有存储过程。为限制其输出,可使用
LIKE
指定一个过滤模式,例如SHOW PROCEDURE STATUS LIKE 'ordertotal';