Mosh
Basic
Join
内连接和外连接
外连接,保留Left或Right侧的所有记录。
- 多的一方(orders): 会有NULL
- 一的一方(customer): 会有重复
内连接:去除含NULL的记录,也会有重复
-- Inner JoinsSELECT order_id, o.customer_id, first_name, last_name FROM orders oJOIN customers c ON o.customer_id = c.customer_id ORDER BY order_id ;SELECT c.customer_id, first_name, last_name, order_id FROM customers cJOIN orders o ON c.customer_id = o.customer_id ORDER BY c.customer_id ;-- LEFT Outer JoinsSELECT order_id, o.customer_id, first_name, last_name FROM orders o LEFTJOIN customers c ON o.customer_id = c.customer_id ORDER BY order_id ;SELECT c.customer_id, first_name, last_name, order_id FROM customers c LEFTJOIN orders o ON c.customer_id = o.customer_id ORDER BY c.customer_id ;-- RIGHT 0uter Joins,注意是c.customer_idSELECT order_id, c.customer_id, first_name, last_name FROM orders o RIGHTJOIN customers c ON o.customer_id = c.customer_id ORDER BY c.customer_id;SELECT c.customer_id, first_name, last_name, order_id FROM customers c RIGHTJOIN orders o ON c.customer_id = o.customer_id ORDER BY order_id ;- SELECT里customer_id加前缀o是因为分不清到底是order中的还是customer中的(或者两个表中有非关联的同名的键,例如product.unit_price和order_item.unit_price,也要明确是哪个表的)
多表连接
-- JOIN Multiple TableSELECTo.order_id,c.first_name,os.name as statusFROM orders oJOIN customers cON o.customer_id = c.customer_idJOIN order_statuses osON o.status = os.order_status_id;
复合主键 composite primary key
order_items
order_item_notes
SELECT oi.order_id,oi.product_id,oin.noteFROM order_items oiJOIN order_item_notes oinON oi.order_id = oin.order_IdAND oi.product_id = oin.product_id;-- 或者SELECT oi.order_id, oi.product_id, oin.noteFROM order_item oiJOIN order_item_notes oinUSING (order_id, product_id);
Across database join
USE sql_store;SELECT oi.order_id, oi.unit_price, p.namefrom order_items oi-- 只需要给不在当前USE的数据库的表加数据库的前缀JOIN sql_inventory.products pON oi.product_id = p.product_id;
自连接 self join
-- Self JoinsSELECTe.employee_id, e.first_name,m.first_name AS managerFROM employee eJOIN employee mON e.reports_to = m.employee_id
using
SELECT c.customer_id, first_name, last_name, order_idFROM customers cJOIN orders oUSING (customer_id);
Outer Join
尽量只使用左连接
-- Multiple outer joinSELECTo.order_id ,o.order_date ,c.first_name as customer,sh.name as shipper,os.name as statusFROM orders ojoin customers con o.customer_id = c.customer_idleft join shippers shon o.shipper_id = sh.shipper_idjoin order_statuses oson o.status = os.order_status_id ;
Unions和“自定义字段”
-- UNIONALL不去除重复SELECT customer_id, first_name, points, 'Bronze' AS typeFROM customers cWHERE points < 2000UNIONSELECT customer_id, first_name, points, 'Silver' AS typeFROM customers cWHERE points BETWEEN 2000 AND 3000UNIONSELECT customer_id, first_name, points, 'GOLD' AS typeFROM customers cWHERE points > 3000ORDER BY type;
CUD
INSERT 插入数据
插入分层数据 hierarchical data
INSERT INTO orders (customer_id, order_date, status)VALUES (1, '2021-04-25', 1);INSERT INTO order_itemsVALUES (LAST_INSERT_ID(), 1, 1, 2.95),(LAST_INSERT_ID(), 2, 1, 3.95);
UPDATE 更新数据
更新多行
设置允许更新多行
UPDATE invoicesSETpayment_total = invoice_total * 0.1,payment_date = due_dateWHERE client_id IN (3,4);
结合子查询(subQuery)和join,子查询一般是和in结合使用,但是不推荐使用
UPDATE invoicesSETpayment_total = invoice_total * 0.3,payment_date = due_dateWHERE client_id IN(SELECT client_idFROM clientsWHERE state IN ('CA','TX'));
DELETE删除数据
结合子查询(subQuery)
DELETE FROM invoicesWHERE invoice_id = (SELECT client_id FROM clients WHERE name = 'Myworks')
复杂查询
WHERE中的子查询
子查询 VS 连接
- 性能 2.可读性。优先性能,然后可读性。具体要看执行计划。
子查询可能用于NOT IN(不包含)多一些
-- 子查询SELECT *FROM products pWHERE product_id NOT IN (SELECT DISTINCT product_idFROM order_items oi);-- 连接SELECTp.product_id ,p.name ,oi.order_idFROM products pLEFT jOIN order_items oiusing (product_id )where oi.order_id IS NULL;
相关子查询
- 非相关子查询,子查询只执行一次,
相关子查询,主查询的每一行子查询都要执行一次
-- 外面的office_id和里面是同一个use sql_hr;SELECT e.employee_id , e.office_id , e.first_name , e.salaryfrom employees ewhere e.salary > (SELECT AVG(salary)from employeeswhere office_id = e.office_id);
IN VS EXISTS
重要!如果IN运算符后写的子查询生成了很大的结果集,会妨碍性能,使用EXISTS能提高性能。
IN: 子查询给外查询返回一个结果集
- EXISTS: 子查询返回一个指令,说明这个子查询中是否有符合这个搜索条件的行
SELECT * from products pWHERE NOT EXISTS (select product_idfrom order_items oiwhere product_id = p.product_id);
ALL关键字
all VS max() ```sql SELECT from order_items oi where quantity > ALL ( SELECT quantity from order_items where product_id = 4 ); SELECT from order_items oi where quantity > ( SELECT MAX(quantity) from order_items where product_id = 4 );
<a name="cicfk"></a>### SELECT子句中的子查询```sqlSELECT invoice_id ,invoice_total,(SELECT AVG(invoice_total) FROM invoices) as invoice_average,invoice_total - (select invoice_average) as differencefrom invoices;
FROM中的子查询
相当于临时表/视图,From中的子查询仅限于简单查询
SELECT * FROM (SELECT invoice_id ,invoice_total,(SELECT AVG(invoice_total) FROM invoices) as invoice_average,invoice_total - (select invoice_average) as differencefrom invoices i) as invoice_summaryWHERE invoice_total IS NOT NULL;
子查询的限制
避免使用子查询,可以把子查询优化为 join 操作。
- 通常子查询在 in 子句中,且子查询中为简单 SQL(不包含 union、group by、order by、limit 从句) 时,才可以把子查询转化为关联查询进行优化。
- 删除中的子查询是同一张表,会产生死锁。
-- 删除全部重复的,错误,原因是:更新这个表的同时又查询了这个表,-- 查询这个表的同时又去更新了这个表,可以理解为死锁。mysql不支持这种更新查询同一张表的操作DELETE FROM student_contactsWHERE name IN (SELECT name FROM student_contacts GROUP BY name HAVING COUNT(1) > 1);
列属性
VARCHAR和CHAR的区别
函数
```sql SELECT CONVERT(“2018-11-30”, DATETIME); SELECT CAST(“2018-11-30” AS DATE);SELECT LAST_INSERT_ID();
SELECT COALESCE(id, user_id, ‘none’) FROM user; SELECT IFNULL(id, ‘none’) FROM user;
<a name="Dn1vF"></a>## AVG平均值```sqlSELECT AVG(salary) from employees;
IF条件
SELECTproduct_id,name,COUNT(*) as orders,IF(COUNT(*) > 1, 'Many times', 'once') as frequenceFROM productsINNER JOIN order_items oiUSING(product_id)GROUP BY product_id, name;
IFNULL
DELIMITER $$CREATE PROCEDURE get_payments(client_id INT(4),payment_method_id TINYINT(2))BEGINSELECT * FROM payments pwhere p.client_id = IFNULL(client_id, p.client_id)and p.payment_method = IFNULL(payment_method_id, p.payment_method);END$$
Case条件
SELECTorder_id,CASEWHEN YEAR(order_date) = YEAR(NOW()) THEN 'Active'WHEN YEAR(order_date) = YEAR(NOW()) - 1 THEN 'Last YEAR'WHEN YEAR(order_date) < YEAR(NOW()) THEN 'Archived'ELSE 'Future'END AS categoryFROM orders;
操作
不推荐的
- implicit join
- natural joins
