-- 连接表 select p.name, o.quantity, o.unit_price from order_items as o join products as p on o.product_id = p.product_id;
-- 连接另一个数据库 select*from order_items as oi join sql_inventory.products p on oi.product_id = p.product_id
-- 自连接 select e.reports_to, e.first_name, m.first_name as manager from employees as e join employees as m on e.reports_to = m.employee_id
-- 多表连接 select p.payment_id, c.name, pm.name from payments as p join clients as c on p.client_id = c.client_id join payment_methods as pm on p.payment_method = pm.payment_method_id
复合主键
1 2 3
-- 复合连接条件 select*from order_items as oi join order_item_notes as oin on oi.order_id = oin.order_Id and oi.product_id = oin.product_id
1 2 3 4 5 6 7 8 9 10 11 12 13
-- 外连接 select p.product_id, p.name, ot.quantity from products as p leftjoin order_items as ot on p.product_id = ot.product_id;
-- 多表外连接 select os.order_date, os.order_id, cs.first_name, ss.name, oss.name from orders as os leftjoin customers as cs on os.customer_id = cs.customer_id leftjoin shippers as ss on os.shipper_id = ss.shipper_id leftjoin order_statuses as oss on os.status = oss.order_status_id -- 自外连接 select e.employee_id, e.first_name, m.first_name as manager from employees as e leftjoin employees as m on e.reports_to = m.employee_id
1 2 3 4
-- using 字句 select ps.date, cs.name as client, ps.amount, pms.name from payments as ps leftjoin clients as cs using(client_id) leftjoin payment_methods as pms on ps.payment_method = pms.payment_method_id
1 2
-- 交叉连接 select*from shippers crossjoin products
1 2 3 4 5 6 7 8 9 10
-- union select customer_id, first_name, points, 'Bronze'as type from customers where points <2000
union select customer_id, first_name, points, 'Silver'as type from customers where points between2000and3000 union select customer_id, first_name, points, 'Gold'as type from customers where points >3000orderby first_name
update orders set comments ='Gold customer' -- 子查询 where customer_id in (select customer_id from customers where points >'3000') -- 删除 deletefrom invoices -- 子查询 where client_id = (select client_id from clients where name ='Myworks')
第五章
聚合函数
1 2 3 4 5 6 7
selectmax(invoice_total), min(invoice_total), avg(invoice_total), sum(invoice_total), count(distinct client_id) as highest from invoices where invoice_date >'2019-07-01'
select client_id, sum(invoice_total) as total_sales from invoices where invoice_date >='2019-07-01' groupby client_id orderby total_sales desc
select ps.date, pms.name as payment_method, sum(ps.amount) as total_payments from payments as ps leftjoin payment_methods as pms on ps.payment_method = pms.payment_method_id groupby ps.date, pms.name
-- having 根据聚合后的数据判断,where根据表中的数据进行判断 -- 在 orders 表中先根据 customer_id 进行分组,每一组都有一些 order_id ,连接 order_items 表,根据 order_id查询 quantity 和 unit_price,这样 customer_id 对应多个 order_id , 而 order_id 又对应多个 product_id,最后调用 sum()方法 select os.customer_id, cs.first_name, sum(ois.quantity * ois.unit_price) as money from orders as os join customers as cs using(customer_id) join order_items as ois using(order_id) where cs.state ='VA' groupby os.customer_id having money >100
-- with rollup 汇总数据 select pms.name, sum(amount) from payments as ps join payment_methods as pms on ps.payment_method = pms.payment_method_id groupby pms.name withrollup
第六章 复杂查询
1 2 3 4 5 6 7 8 9 10 11 12
-- 查找工资高于平均值的员工 select*from employees where employees.salary > (selectavg(employees.salary) from employees)
select*from clients where clients.client_id notin (select invoices.client_id from invoices)
-- 查询购买了 lettuce(product_id = 3) 的顾客 selectdistinct customer_id, first_name, last_name from customers as c join orders as o using (customer_id) join order_items as ois on (o.order_id = ois.order_id) where ois.product_id =3
关键字 all, any
1 2 3 4 5 6
-- invoice_total 大于 all 后面的集合 select*from invoices where invoice_total >all ( select invoice_total from invoices where client_id =3 )
-- = any 等价于 in
相关子查询
1 2 3 4 5 6
-- 对于每一个用户返回他大于它自己的平均值的帐单 select*from invoices as i where i.invoice_total > ( selectavg(invoices.invoice_total) from invoices where invoices.client_id = i.client_id )
EXISTS
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
-- 这是一条包含子查询的查询语句,子查询会返回一个结果集,例如(1, 2, 3...),但当数据量很大时会严重印象性能 select*from clients where client_id in ( select client_id from invoices ) -- 这条语句使用了exists,后面实际上会返回一个结果,true 或者 false select*from clients as c whereexists ( select client_id from invoices where client_id = c.client_id ) SELECT*FROM products wherenotexists ( select product_id from order_items where order_items.product_id = products.product_id )
SELECT* FROM orders whereyear(order_date) >=year(now())
IFNULL, COALESCE
1 2 3 4 5
select order_id, ifnull(shipper_id, 'not assigned') as shipper from orders -- coalesce() 返回参数的第一个非空值 select order_id, coalesce(shipper_id, comments, 'not assigned') as shipper from orders
IF函数, CASE运算符
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
select p.product_id, p.name, count(*) as orders, if(count(*) >1, 'Many times', 'Once') as fre from products as p join order_items using(product_id) groupby product_id, name
SELECT concat(first_name, ' ', last_name) as customer, case when points >3000then'Gold' when points >2000then'Silver' else'Bronze' endas'category' FROM customers
CREATETRIGGER payments_after_insert AFTER INSERTon payments -- 每对payments插入数据,都会触发触发器 FOREACHROW BEGIN UPDATE invoices SET payment_total = payment_total + NEW.amount WHERE invoice_id = NEW.invoice_id; END $$
delimiter ;
delimiter $$
CREATETRIGGER payments_after_delete AFTER DELETEon payments -- 每对payments插入数据,都会触发触发器 FOREACHROW BEGIN UPDATE invoices SET payment_total = payment_total - OLD.amount WHERE invoice_id = OLD.invoice_id; END $$
delimiter ;
1 2 3 4
-- 查找触发器 SHOW TRIGGERS LIKE'payments%' -- 删除触发器 DROPTRIGGER if EXISTS payments_after_insert;
CREATETRIGGER payments_after_insert AFTER INSERTon payments -- 每对payments插入数据,都会触发触发器 FOREACHROW BEGIN UPDATE invoices SET payment_total = payment_total + NEW.amount WHERE invoice_id = NEW.invoice_id; INSERT INTO payments_audit VALUES (NEW.client_id, NEW.date, NEW.amount, 'Insert', NOW()); END $$
delimiter ;
---------------------------------
delimiter $$
DROPTRIGGER if EXISTS payments_after_delete $$
CREATETRIGGER payments_after_delete AFTER DELETEon payments -- 每对payments插入数据,都会触发触发器 FOREACHROW BEGIN UPDATE invoices SET payment_total = payment_total - OLD.amount WHERE invoice_id = OLD.invoice_id; INSERT INTO payments_audit VALUES (OLD.client_id, OLD.date, OLD.amount, 'Delete', NOW()); END $$
delimiter ;
事件
事件是根据计划执行的任务或者一些 SQL 语句
1 2 3 4 5 6 7 8 9
DELIMITER $$ CREATE EVENT yearly_delete_stale_audit_rows ON SCHEDULE EVERY1YEAR STARTS '2019-01-01' ENDS '2029-01-01' DO BEGIN DELETEFROM payments_audit WHERE action_date < NOW() -INTERVAL1YEAR; END $$ DELIMITER ;
第十一章
ACID
原子性
一致性
隔离性
持久性
1 2 3 4 5 6 7 8 9 10 11 12
START TRANSACTION;
INSERT INTO orders (customers_id, order_date, statue) VALUES (1, '2019-01-01', 1);
INSERT INTO order_items VALUES (LAST_INSERT_ID(), 1, 1, 1);
-- 提交所有操作 COMMIT; -- 撤销所有操作 -- ROLLBACK
并发问题
丢失更新
脏读
不可重复读
幻读
隔离级别
读未提交
会遇到所有并发问题
1 2 3 4 5 6 7
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; START TRANSACTION; SELECT points from customers WHERE customer_id =1; COMMIT;
不可重复读
解决了 脏读 问题,但会遇到 不开重复 问题
1 2 3 4 5 6 7 8 9 10
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; START TRANSACTION; SELECT points from customers WHERE customer_id =1; -- 由于不可重复,第二个查询结果可能会与第一个不一致 SELECT points from customers WHERE customer_id =1; COMMIT;
可重复读
解决了 不可重复 问题, 但会遇到 幻读 问题
1 2 3 4 5 6 7
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ; START TRANSACTION; SELECT* from customers WHERE state ='VA'; COMMIT;
第十二章 - 数据类型
第十三章 - 设计数据库
概念模型
逻辑模型
实体模型
主键:唯一标识表里每条记录的列
外键:
外键约束:
复合主键:
第十四章 - 索引
1 2
-- 建立了一个索引 CREATE INDEX idx_state on customers (state);
前缀索引、全文索引、复合索引
1 2 3 4 5 6 7 8 9 10 11 12
-- 每个字符串选择前二十个字符建立索引 CREATE INDEX idx_lastname on customers (last_name(20))
-- 全文索引 CREATE FULLTEXT INDEX idx_title_body on posts (title, body); SELECT*, MATCH(title, body) AGAINST('react redux') FROM posts WHEREMATCH(title, body) AGAINST('react redux')
-- 复合索引 -- 在建立索引时,建议基数更大的放在前面 CREATE INDEX idx_state_points ON customers (state, points)