MySQL 必知必会
主键:一列(或一组列),其值能够唯一区分表中每个行
任意两行都不具有相同的主键值
每一行都必须具有一个主键(不为 NULL)
习惯:
不更新主键列中的值
不重用主键列中的值
不在主键列中使用可能会更改的值
1SHOW DATABASES;2SHOW TABLES;3SHOW COLUMNS FROM klass; -- 返回当前选择的数据库内可用表的列表,可用 DESCRIBE klass; 代替4SHOW STATUS; -- 用于显示广泛的服务器状态信息5SHOW CREATE DATABASE; -- 显示创建特定数据库6SHOW CREATE TABLE; -- 显示创建特定表的MySQL语句7SHOW GRANTS; -- 用来显示授予用户(所有用户或特定用户)的安全权限8SHOW ERRORS; -- 错误信息9SHOW WARNINGS; -- 警告消息1011HELP SHOW;
1SELECT staff_id FROM staff;2SELECT staff_id, wage FROM staff;3SELECT * FROM staff;4SELECT DISTINCT staff_id FROM staff; -- 去重5SELECT * FROM staff LIMIT 5; -- 返回不超过 5 行6SELECT * FROM staff LIMIT 5, 5; -- 下一个 5 行,LIMIT 5 OFFSET 57SELECT staff.staff_id FROM klass.staff;8SELECT city FROM warehouses ORDER BY city; -- city 的字母顺序9SELECT * FROM warehouses ORDER BY size, city; -- 先按 size 排序,再按 city 排序10SELECT * FROM warehouses ORDER BY size DESC, city ASC; -- DESC 降序11SELECT * FROM warehosues WHERE size <> 570;12SELECT * FROM warehosues WHERE size BETWEEN 500 AND 600;13SELECT * FROM order_form WHERE vendor_id IS NOT NULL; -- IS NULL14SELECT * FROM staff WHERE warehouse_id = 'WH2' AND wage > 1230; -- AND 与 OR 中,AND 优先级更高,是用括号避免错误15SELECT * FROM staff WHERE warehouse_id = 'WH2' OR warehouse_id = 'WH1'; -- 与使用 IN 相同16SELECT * FROM staff WHERE warehouse_id IN ('WH2', 'WH1'); -- IN 可配合 SELECT 子句17SELECT * FROM staff WHERE warehouse_id NOT IN ('WH2', 'WH1');18SELECT * FROM vendor WHERE vendor_name LIKE '_通%公司';-- “_”匹配一个,“%”匹配零到多个,通配符有性能问题,必要时使用19SELECT 'hello' REGEXP '[0-9]'; -- 可使用正则,转译用 “\\”20SELECT Concat(warehouse_id, ': ', Trim(city)) AS warehouse_title FROM warehouses; -- 拼接字段,大多数 SQL 使用 + 或 ||,MySQL 使用 Concat,AS 用作别名21SELECT prod_id, quantity, item_price, item_price * quantity AS expanded_price FROM orderitems WHERE order_num = 20005; -- 算数计算字段2223-- 函数不具有可移植性,各个 SQL 的提供不一样24-- 文本处理函数、时间处理函数、数值处理函数25SELECT * FROM warehouses WHERE Lower(warehouse_id) = 'wh1';26SELECT * FROM order_form WHERE Month(`date`) = '06';27SELECT * FROM warehouses WHERE Mod(size, 100) = 0;28-- 聚集函数29SELECT AVG(wage) FROM staff;30SELECT AVG(DISTINCT wage) FROM staff; -- DISTINCT 聚集不同值3132-- 分组33-- WHERE 之后 ORDER BY 之前34-- WHERE 过滤行 HAVING 过滤分组35-- WITH ROLLUP 获得每个分组以及每个分组汇总级别(针对每个分组)的值36SELECT vend_id, COUNT(*) AS prod_num FROM products WHERE prod_price >= 10 GROUP BY vend_id HAVING COUNT(*) >= 2;3738-- 子查询39SELECT cust_name, cust_state, (SELECT COUNT(*) FROM orders WHERE orders.cust_id = customers.cust_id) AS orders FROM customers ORDER BY cust_name;
外键:外键为某个表中的一列,它包含另一个表的主键值,定义了两个表之间的关系
信息不重复,从而不浪费时间和空间
如果信息变动,可以只更新表中的单个记录,相关表中的数据不用改动
由于数据无重复,显然数据是一致的,这使得处理数据更简单
1-- 联结性能消耗大2SELECT * FROM staff, warehouses; -- 笛卡尔积3SELECT * FROM staff, warehouses WHERE staff.warehouse_id = warehouses.warehouse_id;4SELECT * FROM staff INNER JOIN warehouses ON staff.warehouse_id = warehouses.warehouse_id; -- ANSI SQL 首选,但性能不如上一条好(忽略引擎优化)
假如你发现某物品(其ID为DTNTR)存在问题,因此想知道生产该物品的供应商生产的其他物品是否也存在这些问题。此查询要求首先找到 生产ID为DTNTR的物品的供应商,然后找出这个供应商生产的其他物品。 下面是解决此问题的一种方法:
1SELECT prod_id, prod_name2FROM products3WHERE vend_id IN (SELECT vend_id4 FROM products5 WHERE prod_id = 'DTNTR');67SELECT p1.prod_id, p1.prod_name8FROM products AS p1, products AS p29WHERE p1.vend_id = p2.vend_id10 AND p2.prod_id = 'DTNTR'; -- 性能好
join
1SELECT * FROM staff CROSS JOIN warehouses; -- 笛卡尔积2SELECT * FROM staff NATURAL JOIN warehouses; -- 自然连接3SELECT * FROM staff INNER JOIN warehouses ON staff.warehouse_id = warehouses.warehouse_id;4SELECT * FROM staff, warehouses WHERE staff.warehouse_id = warehouses.warehouse_id; -- 内连接5SELECT * FROM staff LEFT OUTER JOIN warehouses ON staff.warehouse_id = warehouses.warehouse_id; -- 左外连接
组合查询
1SELECT * FROM staff WHERE warehouse_id = 'WH2' OR wage >= 1230;23SELECT * FROM staff WHERE warehouse_id = 'WH2'4UNION -- 不包含重复的列5SELECT * FROM staff WHERE wage >= 1230;67SELECT * FROM staff WHERE warehouse_id = 'WH2'8UNION ALL -- 包含重复的列9SELECT * FROM staff WHERE wage >= 1230;1011SELECT * FROM staff WHERE warehouse_id = 'WH2'12UNION13SELECT * FROM staff WHERE wage >= 1230 ORDER BY wage; -- 是最后一个的组成部分,反对所有的结果都有效
插入
1INSERT INTO customers(2 cust_name,3 cust_address,4 cust_city,5 cust_state,6 cust_country)7VALUES (8 'ahab',9 NULL,10 'hb',11 'study',12 'cn'), (13 'lj',14 NULL,15 'cd',16 'study',17 'cn'); -- 不依赖表中列的次序1819INSERT INTO customers(20 cust_id,21 cust_name)22SELECT cust_id, cust_name23FROM cust_new; -- 根据列的次序进行插入
更新删除
1UPDATE customers2SET cust_email = NULL3WHERE cust_name = 'ahab';45DELETE FROM customers6WHERE cust_id = 123;7-- 使用 WHERE,除非要更新删除每一行
创建
1CREATE TABLE IF NOT EXISTS customers ( -- 创建新表时,表名必须不存在,IF NOT EXISTS 只检测表名不检测模式2 cust_id int NOT NULL AUTO_INCREMENT, -- 每个表只允许一个 AUTO_INCREMENT 列,且必须被索引,使用 SELECT last_insert_id() 确定最后一个 AUTO_INCREMENT 值3 cust_name char(50) NOT NULL,4 cust_address char(50) NULL DEFAULT 'cn',5 PRIMARY KEY (cust_id)) ENGINE = InnoDB; -- InnoDB 支持事务处理,MEMORY 功能同 MyISAM 但数据存在内存,速度极快,适合创建临时表,MyISAM 性能极高,支持全文本搜索,但不支持事务处理
更新表
1ALTER TABLE customers2ADD cust_phone char(50);34ALTER TABLE customers5DROP cust_phone char(50);67ALTER TABLE customers8ADD CONSTRAINT fk_customers_school9FOREIGN KEY (cust_school_id) REFERENCES school (school_id),10ADD CONSTRAINT fk_customers_city11FOREIGN KEY (cust_city_id) REFERENCES home (city_id);
删除表
1DROP TABLE customers;
重命名
1RENAME TABLE2 backup_customers TO customers,3 backup_vendor TO vendor;
视图
重用SQL语句。
简化复杂的SQL操作。在编写查询后,可以方便地重用它而不必知道它的基本查询细节。
使用表的组成部分而不是整个表。
保护数据。可以给用户授予表的特定部分的访问权限而不是整个表的访问权限。
更改数据格式和表示。视图可返回与底层表的表示和格式不同的数据。
因为视图不包含数据,所以每次使用视图时,都 必须处理查询执行时所需的任一个检索。如果你用多个联结 和过滤创建了复杂的视图或者嵌套了视图,可能会发现性能 下降得很厉害
ORDER BY可以用在视图中,但如果从该视图检索数据SELECT中也含有ORDER BY,那么该视图中的ORDER BY将被覆盖。
视图不能索引,也不能有关联的触发器或默认值。
视图可以和表一起使用。例如,编写一条联结表和视图的SELECT语句。
1CREATE VIEW <viewname>2DROP VIEW <viewname>3CREATE OR REPLACE VIEW <viewname>45CREATE VIEW orderitemsexpanded AS6SELECT order_num,7 prod_id,8 item_price,9 quantity,10 quantity * item_price AS expanded_price11FROM orderitems;
一般,应该将视图用于检索(SELECT语句) 而不用于更新(INSERT、UPDATE和DELETE)。
存储过程
简单安全高性能
1DELIMITER // -- 使用 // 结束23CREATE PROCEDURE Avg_wage()4BEGIN5 SELECT Avg(wage)6 FROM staff;7END //89DELIMITER ; -- 改回使用 ;1011CALL Avg_wage(); -- 调用1213DROP PROCEDURE IF EXISTS Avg_wage;
1CREATE PROCEDURE show_sum_of_bigger_than_wage(2 IN num INT,3 OUT result INT)4BEGIN5 SELECT Sum(wage) -- 结果只能有一个数据6 FROM staff7 WHERE wage >= num8 INTO result;9END;1011CALL show_bigger_than_wage(1230, @sum_wages);12SELECT @sum_wages;
1CREATE PROCEDURE ordertotal(2 IN onumber INT,3 IN taxable BOOLEAN,4 OUT ototal DECIMAL(8, 2))5COMMENT 'Obtain order total, optionally adding tax'6BEGIN7 DECLEAR total DECIMAL(8, 2);8 DECLEAR taxrate INT DEFAULT 6;910 SELECT Sum(item_price * quantity)11 FROM orderitems12 WHERE order_num = onumber13 INTO total;1415 IF taxable THEN16 SELECT total + (total / 100 * taxrate) INTO total;17 END IF;1819 SELECT total INTO ototal;20END;2122CALL ordertotal(20005, 0, @total) -- 0 == false, !0 == true
游标
MySQL 中只能用于存储过程和函数
1CREATE PROCEDURE processorders()2BEGIN3 DECLEAR done BOOLEAN DEFAULT 0;4 DECLEAR o INT;5 DECLEAR t DECIMAL(8, 2);67 DECLEAR ordernumbers CURSOR8 FOR9 SELECT order_num FROM orders;1011 DECLEAR CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1; -- 当 order_num 为 02000 时,设置 done = 11213 CREATE TABLE IF NOT EXISTS ordertotals(14 order_num INT,15 total DECIMAL(8, 2));1617 OPEN ordernumbers;1819 REPEAT20 FETCH ordernumbers INTO o;21 CALL ordertotal(o, 1, t);22 INSERT INTO ordertotals(order_num, total)23 VALUES (o, t);24 UNTIL done END REPEAT;2526 CLOSE ordernumbers;27END;
触发器
DELETE、INSERT、UPDATE
只有表支持,视图、临时表都不支持
1-- BEFORE 用于数据验证与净化2CREATE TRIGGER neworder AFTER INSERT ON orders FOR EACH ROW SELECT NEW.order_num -- AUTO_INCRMENT 之后确定新生成的值,INSERT 时有一个 NEW 虚表34CREATE TRIGGER deleteorder BEFORE DELETE ON orders5FOR EACH ROW6BEGIN7 INSERT INTO archive_orders(order_num, order_date, cust_id)8 VALUES (OLD.order_num, OLD.order_date, OLD.cust_id); -- DELETE 时有一个 OLD 虚表9END; -- 可使用 BEGIN END 存储多条语句1011-- UPDATE 时有 NEW、OLD 虚表12-- 所有操作中,NEW 可以更新,OLD 只读
事务
事务(transaction)指一组SQL语句;
回退(rollback)指撤销指定SQL语句的过程;
提交(commit)指将未存储的SQL语句结果写入数据库表;
保留点(savepoint)指事务处理中设置的临时占位符(place-holder),你可以对它发布回退(与回退整个事务处理不同)。
只能回退 UPDATE、DELETE、INSERT,不能回退 CREATE、DROP、SELECT
一般使用隐式提交,事务中只能使用 COMMIT
1START TRANSACTION;2DELETE FROM orders WHERE order_num = 12000;3DELETE FROM orders WHERE order_num = 12000; -- 执行出错,不会提交,操作会自动撤回4COMMIT;56-- 保留点7SAVEPOINT delete1;8ROLLBACK TO delete1;
安全管理
1CREATE USER ben IDENTIFIED BY 'p@$$wOrd';2RENAME USER ben TO bufer;3DROP USER bufer;4SHOW GRANTS FOR ben;5GRANTS SELECT ON klass FOR bufer;6SET PASSWORD FOR bufer = Password('n3w p@$$wOrd'); -- 不置顶 user 时是更改自己的密码
维护
1FLUSH TABLES; -- 刷新,保证数据写入磁盘