视图、外键、触发器、存储过程等
1. 视图
视图是一个虚拟的集合。视图并不会存储数据。视图的定义可等价于一组select+join语句。
使用视图的好处:
视图可以简化复杂的查询。视图的定义是基于一个查询声明,这个查询声明可能关联了很多底层的表。使用视图向数据库的使用者隐藏复杂的底层关系。
可以用视图限制特定用户的数据访问权。
视图可以使用可计算的列。假设在有一张order_details表,其中包含product_nums和price_each两列,当我们需要查询order总价时我们就需要查询出结果后在代码中进行计算,如果我们使用视图的话可以在视图中添加一列total_price(product_nums*price_each)。这样就可以直接查询出order的总价。
视图可以帮我们兼容旧系统。计算机领域对旧系统兼容的一种常用的办法就是增加一个适配层适配不同的底层细节并对上层提供统一的接口。视图可以帮助我们兼容不同的底层表。
1.1 创建视图
语法:
CREATE
/*[ALGORITHM = {UNDEFINED | MERGE | TEMPTABLE}]
[DEFINER = { user | CURRENT_USER }]
[SQL SECURITY { DEFINER | INVOKER }]*/
VIEW `$YOUR_DB_NAME`.`$YOUR_VIEW_NAME`
AS
(SELECT * FROM ...);
参数:
ALGORITHM 算法
默认值为UNDEFINED
MERGE:使用视图的语句与视图的定义合并在一起
TEMPTABLE:使用临时表,视图的结果存入临时表
示例:
mysql> CREATE TABLE t (qty INT, price INT);
mysql> INSERT INTO t VALUES(3, 50);
mysql> CREATE VIEW v AS SELECT qty, price, qty*price AS value FROM t;
mysql> SELECT * FROM v;
+------+-------+-------+
| qty | price | value |
+------+-------+-------+
| 3 | 50 | 150 |
+------+-------+-------+
1.2 查看视图
类比于表的查看操作。视图很多操作都可以类比于表,视图类似一种虚拟的表。
1.3 修改视图
有两种办法:
创建视图,如果视图已存在则替换视图:
(1)CREATE OR REPLACE VIEW 视图名称[(column_list)] AS SELECT 语句
ALTER语句:
(2)ALTER VIEW视图名称[(column_list)] AS SELECT 语句
1.4 更新视图
类比于表的更新操作。使用UPDATE语句
1.5 删除视图
类比于表的删除操作。DROP VIEW IF EXISTS $YOUR_VIEW_NAME1,$YOUR_VIEW_NAME2,...$YOUR_VIEW_NAMEn
2. 触发器
2.1 创建触发器
DELIMITER $$
CREATE
/*[DEFINER = { user | CURRENT_USER }]*/
TRIGGER `view`.`tst` BEFORE/AFTER INSERT/UPDATE/DELETE
ON `view`.`<Table Name>`
FOR EACH ROW BEGIN
END$$
DELIMITER ;
创建一个名为`view`.`tst`的触发器。在插入/更新/删除数据之前/之后对有修改的每一行进行
BEGIN END里的语句操作
3. 存储过程和函数
CREATE
[DEFINER = { user | CURRENT_USER }]
PROCEDURE sp_name ([proc_parameter[,...]])
[characteristic ...] routine_body
CREATE
[DEFINER = { user | CURRENT_USER }]
FUNCTION sp_name ([func_parameter[,...]])
RETURNS type
[characteristic ...] routine_body
proc_parameter:
[ IN | OUT | INOUT ] param_name type
func_parameter:
param_name type
type:
Any valid MySQL data type
characteristic:
COMMENT 'string'
| LANGUAGE SQL
| [NOT] DETERMINISTIC
| { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
| SQL SECURITY { DEFINER | INVOKER }
routine_body:
Valid SQL routine statement
在默认情况下,每个例程是与默认db相关联的。要创建和指定db相关的例程,在创建时指定db_name.sp_name(db名.存储过程名)。
MySQL也用创建函数的声明来支持UDFs(user-defined functions)。一个UDF可以看做规则的外部存储的函数。被存储的函数与UDF共享名字空间。
使用CALL声明来调用被存储的过程。要调用被存储的函数,在一个表达式里应用它即可。在表达式验证的时候,函数会返回数值。
创建过程和函数都需要CREATE ROUTINE权限。根据DEFINER的值,还可能要求具有SUPER权限。如果binary logging打开,创建过程需要super权限。
默认情况下,M有SQL自动赋予ALTER ROUTINE和EXECUTE权限给创建例程。修改automatic_sp_privileges系统变量可以修改这一行为。
下面的例子展示了一个带输出的存储过程:
mysql> delimiter //
mysql> CREATE PROCEDURE simpleproc (OUT param1 INT)
-> BEGIN
-> SELECT COUNT(*) INTO param1 FROM t;
-> END//
Query OK, 0 rows affected (0.00 sec)
mysql> delimiter ;
mysql> CALL simpleproc(@a);
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT @a;
+------+
| @a |
+------+
| 3 |
+------+
1 row in set (0.00 sec)
客户端命令delimiter用来把语句的分界符从;变为//。如果不变,遇到“SELECTCOUNT(*)INTO param1 FROM t;”一句时,因;的存在,mysql客户端会认为语句已经结束,并发送这条SQL,但显然此时SQL并没有结束。因此用delimiter修改了一下界定符,当遇到END后的//时,语句才结束。
只有函数才能带RETURNS子句,并且函数必须带有RETURNS子句,它声明了函数返回的类型。函数体必须包含RETURN语句,如果返回的值与声明不符,返回值会被强制转换。
函数的例子:
mysql> CREATE FUNCTION hello (s CHAR(20))
mysql> RETURNS CHAR(50) DETERMINISTIC
-> RETURN CONCAT('Hello, ',s,'!');
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT hello('world');
+----------------+
| hello('world') |
+----------------+
| Hello, world! |
+----------------+
1 row in set (0.00 sec)
定义了一个名为hello的函数,hello()接受一个字符串类型的入参,返回一个常量字符串“Hello, ”+入参+“!”。
函数体可以是单独的一句合法SQL语句,也可以是BEGIN END引用起来的多条语句。复合语句可以包含声明循环和其他控制结构。语法见“Compound-Statement Syntax”
MySQL允许例程包含DDL语句,如CREATE和DROP。MySQL还允许被存储过程包含SQL事物语句例如COMMIT。被存储函数不能包含执行显式的或隐式的COMMIT或ROLLBACK。SQL标准不需要支持这些语句,DBMS厂商可以自行决定是否允许。MySQL是支持的。但是尽量少用,免得日后移植有问题。
返回语句也可以用在被存储过程里。但是禁止包含没有INTO var_list子句的SELECT语句、SHOW语句、EXPLAIN语句、CHECK TABLE语句。返回函数定义的时候就能确定值的变量,会报一个ER_SP_NO_RETSET错误。
被存储例程里不允许使用USE。例程调用的时候,会隐式的调用USE。
COMMENT特性是一个MySQL扩展,可以用来描述存储的例程。此信息由SHOW CREATE PROCEDURE和SHOW CREATE FUNCTION语句显示。
LANGUAGE特性表示写入例程的语言。服务器忽略此特性;只支持SQL例程。
如果对于相同的输入参数总是产生相同的结果,则例程被认为是“确定性的”,否则为“不确定性”。如果在例程定义中既没有给定确定也没有确定,则默认值不是确定的。要声明函数是确定性的,您必须明确指定DETERMINISTIC。
4. 外键
外键的好处:可以使得两张表关联,保证数据的一致性和实现一些级联操作;
外键的定义语法:
[CONSTRAINT symbol] FOREIGN KEY [id] (index_col_name, ...)
REFERENCES tbl_name (index_col_name, ...)
[ON DELETE {RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT}]
[ON UPDATE {RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT}]
该语法可以在 CREATE TABLE 和 ALTER TABLE 时使用,如果不指定CONSTRAINT symbol,MYSQL会自动生成一个名字。
ON DELETE、ON UPDATE表示事件触发限制,可设参数:
RESTRICT(限制外表中的外键改动)
CASCADE(跟随外键改动)
SET NULL(设空值)
SET DEFAULT(设默认值)
NO ACTION(无动作,默认的)
搞个例子,简单演示一下使用,做dage和xiaodi两个表,大哥表是主键,小弟表是外键:
建表:
2 `id` int ( 11 ) NOT NULL auto_increment,
3 `name` varchar ( 32 ) default '' ,
4 PRIMARY KEY (`id`)
5 ) ENGINE = InnoDB DEFAULT CHARSET = latin1;
6
7 CREATE TABLE `xiaodi` (
8 `id` int ( 11 ) NOT NULL auto_increment,
9 `dage_id` int ( 11 ) default NULL ,
10 `name` varchar ( 32 ) default '' ,
11 PRIMARY KEY (`id`),
12 KEY `dage_id` (`dage_id`),
13 CONSTRAINT `xiaodi_ibfk_1` FOREIGN KEY (`dage_id`) REFERENCES `dage` (`id`)
14 ) ENGINE = InnoDB DEFAULT CHARSET = latin1;
插入个大哥:
2 Query OK, 1 row affected ( 0.01 sec)
3 mysql > select * from dage;
4 + -- --+--------+
5 | id | name |
6 + -- --+--------+
7 | 1 | 铜锣湾 |
8 + -- --+--------+
9 1 row in set ( 0.00 sec)
插入个小弟:
2 Query OK, 1 row affected ( 0.02 sec)
3
4 mysql > select * from xiaodi;
5 + -- --+---------+--------------+
6 | id | dage_id | name |
7 + -- --+---------+--------------+
8 | 1 | 1 | 铜锣湾_小弟A |
9 + -- --+---------+--------------+
把大哥删除:
2 ERROR 1451 ( 23000 ): Cannot delete or update a parent row: a foreign key constraint fails (`bstar / xiaodi`, CONSTRAINT `xiaodi_ibfk_1` FOREIGN KEY (`dage_id`) REFERENCES `dage` (`id`))
提示:不行呀,有约束的,大哥下面还有小弟,可不能扔下我们不管呀!
插入一个新的小弟:
2 ERROR 1452 ( 23000 ): Cannot add or update a child row: a foreign key constraint fails (`bstar / xiaodi`, CONSTRAINT `xiaodi_ibfk_1` FOREIGN KEY (`dage_id`) REFERENCES `dage` (`id`))
3
提示:小子,想造反呀!你还没大哥呢!
把外键约束增加事件触发限制:
2
3 CONSTRAINT `xiaodi_ibfk_1` FOREIGN KEY (`dage_id`) REFERENCES `dage` (`id`)
4
5 mysql > alter table xiaodi drop foreign key xiaodi_ibfk_1;
6 Query OK, 1 row affected ( 0.04 sec)
7 Records: 1 Duplicates: 0 Warnings:
8 mysql > alter table xiaodi add foreign key (dage_id) references dage(id) on delete cascade on update cascade ;
9 Query OK, 1 row affected ( 0.04 sec)
10 Records: 1 Duplicates: 0 Warnings: 0
再次试着把大哥删了:
2 Query OK, 1 row affected ( 0.01 sec)
3
4 mysql > select * from dage;
5 Empty set ( 0.01 sec)
6
7 mysql > select * from xiaodi;
8 Empty set ( 0.00 sec)
得,这回对应的小弟也没了,没办法,谁让你跟我on delete cascade了呢!
例子说明的应该蛮清楚了吧,其他功能对应手册自己实践吧!:-)
2. 查询账号权限
show grants for 你的用户;
查看所有用户(需要高权限):SELECT DISTINCT CONCAT('User: ''',user,'''@''',host,''';') AS query FROM mysql.user;
参考文献:
作者:孙进不后退 链接:http://www.jianshu.com/p/b11430bc4fba 來源:简书
MySQL手册