CREATE PROCEDURE productpricing() BEGIN SELECT Avg(prod_price) AS priceaverage FROM products; END;
DELEMITER:指定新的语句分隔符,避免;被 mysql 命令行实用程序解释为存储过程的成分
4、删除存储过程:DROP PROCEDURE
5、使用参数
存储过程的参数允许的数据类型与表中一致
记录集不是允许的类型。记录集:从指定数据库中检索到的数据的集合
创建布尔值:IN 参数名 BOOLEAN
IF / ELSEIF / ELSE 子句
6、检查存储过程:SHOW CREATE PROCEDURE
获取详细信息的存储过程列表:SHOW PROCUDURE STATUS
游标 cursor
1、使用游标
必须先声明再打开,结束后关闭
创建与访问:DECLARE / FETCH
打开与关闭:OPEN / CLOSE CURSOR
1 2 3 4 5 6 7 8 9 10 11 12 13
CREATE PROCEDURE processorders() BEGIN DECLARE ordernumbers CURSOR FOR SELECT order_num FROM orders END;
-- 打开游标 OPEN ordernumbers; -- 关闭游标 CLOSE ordernumbers; -- 检索order_num列到一名为o的局部变量中(不处理检索出的数据) FETCH ordernumbers INTO o;
UNTIL done END REPEAT:反复执行直到布尔值 done 为真
手动退出:LEAVE
CONTINUE HANDLER:条件出现时才被执行
1 2
DECLARE done BOOLEAN DEFAULT 0; DECLARE CONTINUE HANDLER FOR SQLSTATE ‘02000’ SET done = 1;
说明在 SQLSTATE ‘02000’出现时,把 done 的值从默认值 0 设置为 1
2、DECLARE 的次序
定义顺序:DECLARE 定义的局部变量 - 游标 - 句柄
句柄(Handle):用来标识对象或者项目的标识符
触发器
1、需给出信息:
最好每个数据库中触发器名称唯一
关联表
应响应活动与执行时机
2、创建:CREATE TRIGGER
相应以下任意语句:DELETE INSERT UPDATE
1 2
CREATE TRIGGER newproduct AFTER INSERT ON products FOR EACH ROW SELECT 'Product added'
仅表可用触发器,视图不行
每张表最多支持 6 个触发器(3 种语句 * 2 个时机)
某时机前触发 BEFORE 失败:则若有 AFTER 触发器,默认不执行
3、删除:DROP TRIGGER
4、使用
可引用 NEW 虚拟表,以访问被插入行
可在 BEFORE INSERT 触发器中更新 NEW 表中的值
对于 AUTO_INCREMENT,INSERT 前置 0,后为新值
DELETE 触发器可引用 OLD 访问被删除行
仅只读,不可再更新
BEFORE DELETE 相对 AFTER ~ 优点:不可存档,DELETE 本身将被放弃
1 2 3 4 5 6
CREATE TRIGGER deleteorder BEFORE DELETE ON orders FOR EACH ROW BEGIN INSERT INTO archive_orders(order_num, order_date, cust_id); VALUES(OLD.order_num, OLD.order_date, OLD.cust_id); END;
UPDATE 触发器可用 NEW、OLD
BEFORE UPDATE 触发器中,NEW 中可改动的 UPDATE 值可被更新
OLD 表仅可读,不可更新
触发器是自动执行的,可能需要特殊权限
不支持在触发器中使用 CALL 语句
5、展望
内容仍较初级,有诸多改进空间
可用于保证数据一致性、创建审计跟踪
事务处理 transaction processing
1、一些概念
事务:一组 SQL 语句
回退 rollback:撤销指定语句的过程
(隐含)提交 commit:(自动)将未存储语句写入表
保留点 savepoint:设置的临时占位符(placeholder),可回退
2、使用事务处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
-- 回退 SELECT * FROM ordertotals; START TRANSACTION; DELETE FROM ordertotals; SELECT * FROM ordertotals; ROLLBACK; SELECT * FROM ordertotals;
-- 提交(例中两个DELETE都返回成功才COMMIT) START TRANSACTION; DELETE FROM orderitems WHERE order_num = 20010; DELETE FROM orders WHERE order_num = 20010; COMMIT;
-- 使用保留点 SAVEPOINT delete1; ROLLBACK TO delete1;
回退后不再显示空结果
三种操作执行流结束后事务均会自动关闭
保留点个数越多越好,灵活回退
3、更改默认的提交行为
仅针对每个连接,不针对服务器
1 2
-- 此时不自动提交 SET autocommit = 0;
* 全球化与本地化
1、使用
显示字符集、校对顺序:SHOW CHARACTER SET / COLLATION;
显示特定字符集:SHOW VARIABLES LIKE ‘character%’;
与创建表不同的校对顺序查询
1 2
SELECT * FROM customers; ORDER BY lastname, firstname, CLLATE latin1_general_cs;
2、串在字符集间的转换:Cast () / Conver () 函数
安全管理
1、访问控制
谨慎使用 root 登录
给予用户适当的访问权
2、管理用户
获取所用用户列表
1 2
USE mysql; SELECT user FROM user;
创建用户账号
IDENTIFIED BY:指定纯文本口令
或使用 GRANT / INSERT 语句(不好)
1
CREATE USER bob IDENTIFIED BY 'mypassword'
重命名:RENAME USER
删除:DROP USER
设置管理权限:SHOW GRANTS FOR 用户名
* 表示无权限
3、GRANT / REVOKE 语句
需给出的信息:需授予权限 所需库或表 用户名
1 2 3 4 5 6
-- 给予权限 SHOW GRANTS FOR bob; GRANT SELECT ON crashcourse.* to bob; -- 撤销权限 REVOKE GRANTS FOR bob; REVOKE SELECT ON crashcourse.* to bob;
SELECT cust-name, cust_contact FROM customers WHERE cust_id IN (SELECT cust_id FROM orders WHERE order_num IN (SELECT order_num FROM orderitems WHERE prod_id = 'TNT2'));
SELECT vend_name, prod_name, prod_price FROM vendors, products WHERE vendors.vend.id = products.vend.id ORDER BY vend_name, prod_name;
笛卡尔积:由没有联结条件的表关系返回的结果(def 离散)
因而需保证所有联结都有 WHERE 子句
交叉联结 cross join
4、* 内部联结
1 2 3
SELECT vend_name, prod_name, prod_price FROM vendors INNER JOIN products ON vendors.vend.id = products.vend_id;
联结条件:使用特定的 ON 子句给出
5、实例:相对子查询优化效率(具体问题具体分析)
1 2 3 4 5
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';
高级联结
1、使用表别名
1 2 3 4
SELECT Concat(RTrim(vend_name), '(', RTrim(vend_country), ')') AS vend_title FROM vendors ORDER BY vend_name;
作用:
缩短语句
允许单条 SELECT 多次使用相同表,如:
1 2 3 4 5
SELECT cust_name, cust_contact FROM customers AS a, orders AS i, orderitems AS ai WHERE a.cust_id = i.cust_id AND ai.order_num = i.order_num AND prod_id = 'TNT2';
2、自联结
作为外部语句来替代从相同表中检索使用的子查询
1 2 3 4
SELECT p1.prod_id, p1.prod_name FROM products AS p1, products AS p2 WHERE p1.vend_id = p2.vend_id AND p2.prod_id = 'DTNTR';
注:实际问题,效率需具体分析,不一定优于子查询
1 2 3 4 5
SELECT p1.prod_id, p1.prod_name FROM products WHERE vend_id = (SELECT vend_id FROM products WHERE prod_id = 'DTNTR');
3、自然联结
排除多次出现的列,仅使每个列返回一次(仅选择唯一列)
通常对表使用通配符 SELECT *
1 2 3 4 5 6
SELECT c.*, o.order_num, o.order_date, oi.prod_id, oi.quantity, OI.item_price FROM customers AS c, orders AS o, orderitems AS oi WHERE c.cust_id = o.cust_id AND oi.order_num = o.order_num AND prod_id = 'FB';
4、外部联结 OUTER JOIN (较少使用)
联结包含了没有关联行的行
类型:左外部联结 右外部联结
使用时需要用 RIGHT / LEFT 关键字指定行范围(从右 / 左侧的表中选择所有行)
mysql 不支持 *= 等一系列简化操作符!
可通过颠倒 FROM / WHERE 子句互换使用
5、带聚集函数的联结
组合查询
1、并 union:执行多个查询,将结果作为单个查询结果集返回
使用情景:单个查询从多个表返回类似数据;对单个表多个查询,按单个返回
多个 WHERE 子句的单条查询可以达到相同的作用
使用于较为复杂过滤条件
2、UNION 规则
由两条及以上 SELECT 语句构成
每个查询包含相同表达式
列数据类型兼容
3、功能
自动去重(默认)
返回所有匹配行:UNION ALL
与 ORDER BY 排序:必须出现在最后一条 SELECT 语句后
1 2 3 4 5 6 7 8
SELECT vend_id, prod_id, prod_price FROM products WHERE prod_price <= 5 UNION SELECT vend_id, prod_id, prod_price FROM products WHERE vend_id IN(1001, 1002) ORDER BY vend_id, prod_price;
全文本搜索
1、支持的数据库引擎:MyISAM(InnoDB 不支持)
2、使用全文本搜索:随数据改变不断索引被搜索的列
FULLTEXT ():索引列
不要在导入数据使用,降低导入速率
Match ():指定被搜索的列
使用值必须与 FULLTEXT () 中定义相同
多个列索引,其次序与 FULLTEXT () 中保持一致
Against ():指定要使用的搜索表达式
文本中,靠前的行的给定词等级值高于后继
对多个搜索项,包含更多匹配词的行等级值更高
索引的搜索速度相当快
3、查询扩展
1 2 3
SELECT note_text FROM productnotes WHERE Match(note_text) Against('anvils' WITH QUERY EXPANSION);
步骤
先进行全文本搜索
检查匹配行,判定有用词(与给定词相关词)
运用有用词和原给定词再次进行全文本搜索
文本行数越多,查询扩展结果越好
4、布尔文本搜索
1 2 3
SELECT note_text FROM productnotes WHERE Match(note_text) Against('heavy -rope*' IN BOOLEAN MODE)
匹配词 heavy,但排除任何包含以 rope 开始的词
布尔方式 boolean mode
提供:匹配词 排斥词 排列提示 表达式分组 etc.
没有定义 FULLTEXT 索引也可使用
全文本布尔操作符(P128)
如 + /- :包含 / 排除
< >:包含,并减少 / 增加等级值
-:取消一个
*:词尾通配符
5、默认注意事项
短词(<=3 个字符的词)从索引中被排除
内建的非用词(stopword)被忽略
出现行数高于 50% 的词作为非用词忽略
少于三行的文本不返回结果
忽略词中的单引号
中文、日文等不具有词分隔符的语言无法正确返回结果
数据插入 INSERT
1、插入完整行
每组值用一对圆括号括起来,以逗号分隔
多使用 cust_id 明确插入,可在表结构改变后继续发挥作用
INSERT 一般无输出结果
必须给出 VALUES 的正确数目;不提供列名则必须对每列给出一个值
1 2 3 4 5 6
INSERT INTO customers(cust_name, cust_contact, cust_country) VALUES('Peter', NULL, 'UK');
省略列:NULL
表的定义中给出默认值:不给定值时使用
提高整体性能:用 INSERT LOW_PRIORITY INTO 降低插入的优先级
2、插入多行
使用多条 INSERT 语句(可一次性提交)
3、插入检索所得数据
1 2 3 4 5 6 7 8 9 10
INSERT INTO customers(cust_name, cust_contact, cust_country) VALUES('Peter', NULL, 'UK'); SELECT cust_name, cust_contact, cust_country FROM custnew;
其中,列名不一定匹配,仅作顺序填充
可包含 WHERE 子句以过滤插入数据
更新和删除数据
1、更新:UPDATE 语句
不省略 WHERE 语句,避免更新表中所有行
语句组成:要更新的表名 列名及其新值 要更新行的条件
1 2 3 4
UPDATE IGNORE customers SET cust_email = 'balabala@qq.com', cust_name = 'bob' WHERE cust_id = 10005;