SQL学习总结
文章目录
- 第二章
- SELECT
- WHERE
- 运算符:AND, OR, NOT, IN, BETWEEN, LIKE, REGEXP, NULL
- 字句: ORDER BY, LIMIT
- 第三章
- JOIN ON
- 第四章
- INSERT, CREATE, UPDATE, DELETE
- 第五章
- 聚合函数
- ORDER BY, HAVING, WITH ROLLUP
- 第六章 复杂查询
- 关键字 all, any
- 相关子查询
- EXISTS
- SELECT, FROM 中的子查询
- 第七章
- 数值函数
- 字符串函数
- 日期函数
- IFNULL, COALESCE
- IF函数, CASE运算符
- 第八章 - 视图
- 第九章 - 存储过程
- 函数
- 第十章 触发器
- 事件
- 第十一章
- 并发问题
- 隔离级别
- 读未提交
- 不可重复读
- 可重复读
- 第十二章 - 数据类型
- 第十三章 - 设计数据库
- 第十四章 - 索引
- 前缀索引、全文索引、复合索引
- 覆盖索引
https://www.bilibili.com/video/BV1UE41147KC
第二章
from -> where -> order by .. (desc) -> limit
SELECT
select *
from customers
where customer_id = 1
order by first_name;
select first_name, points + 10 as discount_factor from customers
select distinct state from customers
WHERE
select * from customers where state != 'VA'
select * from orders where order_date > '2018-01-01'
-- 运算符 >, <, >=, <=, !=, <>
运算符:AND, OR, NOT, IN, BETWEEN, LIKE, REGEXP, NULL
select * from customers where birth_date > '1990-01-01' or points > 1000;
select * from customers where birth_date > '1800-01-01' and points > 1000;
select * from customers where not birth_date > '1990-01-01'
SELECT * FROM products where quantity_in_stock in (49, 38, 72)
SELECT * FROM customers where birth_date between '1990-01-01' and '2000-01-01'
SELECT * FROM customers where address like '%trail%';
SELECT * FROM customers where phone like '%9'
select * from customers where first_name regexp 'ELKA|AMBUR';
select * from customers where last_name regexp 'ey$|on$';
select * from customers where last_name regexp '^my|se';
select * from customers where last_name regexp 'b[ru]';
select * from orders where shipper_id is null;
字句: ORDER BY, LIMIT
select * from customers order by points desc limit 3;
第三章
JOIN ON
-- 连接表
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
复合主键
-- 复合连接条件
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
-- 外连接
select p.product_id, p.name, ot.quantity from products as p
left join 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
left join customers as cs on os.customer_id = cs.customer_id
left join shippers as ss on os.shipper_id = ss.shipper_id
left join 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
left join employees as m on e.reports_to = m.employee_id
-- using 字句
select ps.date, cs.name as client, ps.amount, pms.name from payments as ps
left join clients as cs using(client_id)
left join payment_methods as pms on ps.payment_method = pms.payment_method_id
-- 交叉连接
select * from shippers cross join products
-- 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 between 2000 and 3000
union
select customer_id, first_name, points, 'Gold' as type from customers
where points > 3000 order by first_name
第四章
INSERT, CREATE, UPDATE, DELETE
-- insert into
insert into products (name, quantity_in_stock, unit_price)
value ('apple', 114, 1.14), ('pen', 1145, 1.45), ('banaer', 104, 10.4)
-- 创建表
create table invoices_archive
-- 子查询
select invoices.invoice_id, clients.name, invoices.payment_date from invoices
left join clients using(client_id)
where invoices.payment_date is not null
-- 更新多行
update customers set points = points + 50 where birth_date < '1990-01-01'
update orders set comments = 'Gold customer'
-- 子查询
where customer_id in (select customer_id from customers where points > '3000')
-- 删除
delete from invoices
-- 子查询
where client_id = (select client_id from clients where name = 'Myworks')
第五章
聚合函数
select max(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'
ORDER BY, HAVING, WITH ROLLUP
-- 除了from 其他关键字是可选的
from -> where -> group by -> order by
select client_id, sum(invoice_total) as total_sales
from invoices
where invoice_date >= '2019-07-01'
group by client_id
order by total_sales desc
select ps.date, pms.name as payment_method, sum(ps.amount) as total_payments
from payments as ps
left join payment_methods as pms on ps.payment_method = pms.payment_method_id
group by 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'
group by 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
group by pms.name with rollup
第六章 复杂查询
-- 查找工资高于平均值的员工
select * from employees
where employees.salary > (select avg(employees.salary) from employees)
select * from clients
where clients.client_id not in (select invoices.client_id from invoices)
-- 查询购买了 lettuce(product_id = 3) 的顾客
select distinct 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
-- invoice_total 大于 all 后面的集合
select * from invoices where invoice_total > all (
select invoice_total from invoices where client_id = 3
)
-- = any 等价于 in
相关子查询
-- 对于每一个用户返回他大于它自己的平均值的帐单
select * from invoices as i
where i.invoice_total > (
select avg(invoices.invoice_total) from invoices
where invoices.client_id = i.client_id
)
EXISTS
-- 这是一条包含子查询的查询语句,子查询会返回一个结果集,例如(1, 2, 3...),但当数据量很大时会严重印象性能
select * from clients
where client_id in (
select client_id from invoices
)
-- 这条语句使用了exists,后面实际上会返回一个结果,true 或者 false
select * from clients as c
where exists (
select client_id
from invoices
where client_id = c.client_id
)
SELECT * FROM products
where not exists (
select product_id from order_items
where order_items.product_id = products.product_id
)
SELECT, FROM 中的子查询
第七章
数值函数
round()
truncate()
ceiling()
floor()
abs()
rand()
字符串函数
length()
upper()
lower()
ltrim()
rtrim()
trim()
left()
right()
substring()
locate()
replace()
concat()
日期函数
now()
curdate()
curtime()
extract(day|year from now())
SELECT *
FROM orders
where year(order_date) >= year(now())
IFNULL, COALESCE
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运算符
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)
group by product_id, name
SELECT
concat(first_name, ' ', last_name) as customer,
case
when points > 3000 then 'Gold'
when points > 2000 then 'Silver'
else 'Bronze'
end as 'category'
FROM customers
第八章 - 视图
视图不存放数据,它只是查询的结果
视图可以简化查询,也可以提供一层抽象
CREATE VIEW clients_balance AS
SELECT
invoices.client_id,
clients.`name`,
SUM(invoices.invoice_total - invoices.payment_total) as balance
from invoices
LEFT JOIN clients USING(client_id)
GROUP BY invoices.client_id
-- 如果视图中没有使用 union、聚合函数。。。那么这个视图是可更新的
CREATE OR REPLACE VIEW invoices_with_balance AS
SELECT
invoice_id,
number,
client_id,
invoice_total,
payment_total,
invoice_total - payment_total as balance,
invoice_date,
due_date,
payment_date
from invoices
where (invoice_total - payment_total) > 0
CREATE OR REPLACE VIEW invoices_with_balance AS
SELECT
invoice_id,
number,
client_id,
invoice_total,
payment_total,
invoice_total - payment_total as balance,
invoice_date,
due_date,
payment_date
from invoices
where (invoice_total - payment_total) > 0
-- 这条语句会防止 update 或者 delete 将行从视图中删除
WITH CHECK OPTION
第九章 - 存储过程
存储过程是一组为了完成特定任务而预先编译并存储在数据库中的 SQL 语句集合。你可以把它想象成编程里的函数,它接收输入参数,执行一系列操作,还能返回结果
delimiter $$
CREATE PROCEDURE get_clients()
BEGIN
SELECT * from clients;
end$$
delimiter ;
delimiter $$
CREATE PROCEDURE get_invoices_with_balance()
BEGIN
-- 视图
SELECT * from invoices_with_balance
where balance > 0;
end$$
delimiter ;
-- 参数
CREATE DEFINER=`root`@`%` PROCEDURE `get_invoices_by_client`(client_id int)
BEGIN
SELECT * from invoices
WHERE invoices.client_id = client_id;
END
CREATE DEFINER=`root`@`%` PROCEDURE `get_payments`(client_id INT(4), payment_method_id TINYINT(1))
BEGIN
SELECT * FROM payments
WHERE payments.client_id = IFNULL(client_id, payments.client_id) AND
payments.payment_method = IFNULL(payment_method_id, payments.payment_method);
END
函数
函数只能返回单一值
第十章 触发器
触发器是在插入、更新和删除语句前后自动执行的一堆SQL代码
delimiter $$
CREATE TRIGGER payments_after_insert
AFTER INSERT on payments
-- 每对payments插入数据,都会触发触发器
FOR EACH ROW
BEGIN
UPDATE invoices
SET payment_total = payment_total + NEW.amount
WHERE invoice_id = NEW.invoice_id;
END $$
delimiter ;
delimiter $$
CREATE TRIGGER payments_after_delete
AFTER DELETE on payments
-- 每对payments插入数据,都会触发触发器
FOR EACH ROW
BEGIN
UPDATE invoices
SET payment_total = payment_total - OLD.amount
WHERE invoice_id = OLD.invoice_id;
END $$
delimiter ;
-- 查找触发器
SHOW TRIGGERS LIKE 'payments%'
-- 删除触发器
DROP TRIGGER if EXISTS payments_after_insert;
delimiter $$
DROP TRIGGER if EXISTS payments_after_insert $$
CREATE TRIGGER payments_after_insert
AFTER INSERT on payments
-- 每对payments插入数据,都会触发触发器
FOR EACH ROW
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 $$
DROP TRIGGER if EXISTS payments_after_delete $$
CREATE TRIGGER payments_after_delete
AFTER DELETE on payments
-- 每对payments插入数据,都会触发触发器
FOR EACH ROW
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
语句
DELIMITER $$
CREATE EVENT yearly_delete_stale_audit_rows
ON SCHEDULE
EVERY 1 YEAR STARTS '2019-01-01' ENDS '2029-01-01'
DO BEGIN
DELETE FROM payments_audit
WHERE action_date < NOW() - INTERVAL 1 YEAR;
END $$
DELIMITER ;
第十一章
ACID
- 原子性
- 一致性
- 隔离性
- 持久性
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
并发问题
- 丢失更新
- 脏读
- 不可重复读
- 幻读
隔离级别
读未提交
会遇到所有并发问题
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
START TRANSACTION;
SELECT points
from customers
WHERE customer_id = 1;
COMMIT;
不可重复读
解决了 脏读 问题,但会遇到 不开重复 问题
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;
可重复读
解决了 不可重复 问题, 但会遇到 幻读 问题
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
START TRANSACTION;
SELECT *
from customers
WHERE state = 'VA';
COMMIT;
第十二章 - 数据类型
第十三章 - 设计数据库
- 概念模型
- 逻辑模型
- 实体模型
- 主键:唯一标识表里每条记录的列
- 外键:
- 外键约束:
- 复合主键:
第十四章 - 索引
-- 建立了一个索引
CREATE INDEX idx_state on customers (state);
前缀索引、全文索引、复合索引
-- 每个字符串选择前二十个字符建立索引
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
WHERE MATCH(title, body) AGAINST('react redux')
-- 复合索引
-- 在建立索引时,建议基数更大的放在前面
CREATE INDEX idx_state_points ON customers (state, points)
覆盖索引
在建立二级索引时,主键会自动加入二级索引中