Skip to content

🔗 联结表

[!quote] 联结表

联结表 是一种将两个多个表中的数据通过某些共同的值关联起来的操作

[!hint] 大多数 DBMS,处理联结的速度 >> 子查询

联结表分为

  • 【内联结】:结果只包含所有参与联结的表中,都有匹配记录的行
  • 【自联结】:将一个表视为两个不同的表进行联结
  • 【外联结】:允许从至少一个表中选择所有记录,即使这些记录在另一个表中没有匹配的记录

[!hint] 笛卡尔积 如果在联结时,没有加上限制条件,则是把 表 A 的每一行匹配 表 B 的每一行,所以如果此种情况 SELECT * 时,则查询的行数 = 表 A 行数 * 表 B 行数

内联结

  • 隐式内联结 SELECT 字段 FROM 表1,表2 WHERE 条件; 【表 1 和表 2 就通过了 WHERE 联结在了一起】

  • 显示内联结 SELECT 字段 FROM 表1 [INNER] JOIN 表2 ON 联结条件;

sql
select user.id, user.name, user.age, table_name.产品ID 
from user 
INNER JOIN table_name ON table_name.id = user.id;

---
|id|name|age|            
|:-:|:-:|:-:|
|123|陈冠希|45|
|11|刘诗诗|14|
|444|吴彦祖|4|
     +
|产品ID|id|
|:-:|:-:|
|乌鸦 |444|
|狗|11|
|老虎|123|

|id|name|age|产品ID|
|:-:|:-:|:-:|:-:|
|123|陈冠希|45|老虎|
|444 |吴彦祖|4|乌鸦|
|11 |刘诗诗|14|狗|

自联结

sql
//使用自联结的方式来实现
SELECT c1.id, c1.name, c1.contact
FROM customers AS c1,
     customers AS c2
WHERE c2.contact = 'jim'    //经过这个条件筛选过后,c2表中只剩下一条记录
  AND c1.name = c2.name;     //c1表中的name与c2表中的那一条记录进行比较

//如果使用子查询的方式来实现:
SELECT id, name, contact
FROM customers
WHERE name = (SELECT name FROM customers WHERE contact = 'Jim');

---

|id|name|contact|
|:-:|:-:|:-:|
|100|Fun123|Jim|
|101|Fun566|Tom|     × 2
|102|Fun123|Mike|
|103|Fun578|July|

|100|Fun123|Jim|
|102|Fun123|Mike|

外联结

  • 左外联结 SELECT 字段列表 FROM 表A LEFT JOIN 表B ON 联结条件; 返回左表中所有的行,以及右表中满足条件的行
sql
SELECT customers.id, orders.numbers
FROM customers
         LEFT JOIN orders ON customers.id = orders.id;

---
|id|name|contact|
|:-:|:-:|:-:|
|100|Fun123|Jim|
|101|Fun566|Tom|  
|102|Fun123|Mike|
|103|Fun578|July|
    +
|id|numbers|
|:-:|:-:|
|101|null|
|102 |9|
|103 |229|

|id|numbers|
|:-:|:-:|
|100|null|
|101|null|
|102|9|
|103|229|
  • 右外联结:返回右表中所有的行,以及左表中满足条件的行【一般不使用

视图

[!quote] 视图

视图 是一组定义好的查询语句,可以看成是一张虚拟的表,而不是一个实际存储的数据集,

  • 优点

    • 可以使用视图封装某一组复杂的语句,进行重用,简化复杂的 SQL 操作
  • 缺点

    • 视图不能索引
    • 视图不能有关联的触发器:视图本身不能包含触发器,因为触发器是与表关联的

视图只能被 `SELECT` ,不能进行其他的 CUD 操作

  • 创建视图 CREATE VIEW 视图名 AS 语句;
sql
CREATE VIEW ProductCustomers AS
​​​​ 
SELECT cust_name, cust_contact, prod_id
​​​​ 
FROM Customers, Orders, OrderItems
​​​​
WHERE Customers.cust_id = Orders.cust_id
​​​​ 
	AND OrderItems.order_num = Orders.order_num;​​
  • 删除视图 DROP VIEW 视图名;

  • 使用视图

sql
​​​​​​SELECT cust_name, cust_contact
​​​​
FROM ProductCustomers
​​​​
WHERE prod_id = 'RGAN01';​​

避免使用多个联结创建复杂的视图过滤创建复杂的视图,或者嵌套视图,这样会导致性能下降

物化视图

[!quote] 物化视图 物化视图 是存储了实际数据的表,需要定期刷新以保持数据的最新状态,用于性能优化,特别是在需要频繁访问复杂查询结果的场景中

  • 可以包含索引

创建物化视图需要数据库或表级别的 CREATE 权限,刷新物化视图需要 INSERT 权限,以及物化视图所涉及的所有表的相关列(或整个表)的 SELECT 权限。创建物化视图时可以使用普通表定义中的参数,如分区键、分布键、索引等,并且可以定义索引来提高查询性能。

MySQL 的物化视图可以通过创建一个实际的表来实现,这个表存储了需要查询的数据,并且可以定期刷新以保证数据的准确性。物化视图的刷新可以通过手动触发或使用触发器、事件来实现增量刷新

[!hint] 区分 视图 与 存储过程

  • 视图 只是一组 SELECT 语句,帮你简化操作,在你需要时执行,所以视图只能 SELECT ,不能 CUD
  • 存储过程 是一组 SQL 语句【CRUD】,你可以传入参数,它可以帮你实现一组行为,类比 Java 中的函数

存储过程

[!quote] 存储过程 存储过程 是一组预编译的 SQL 语句【CRUD】,存储在数据库中以便重复使用。存储过程就像是定义了一组复杂的行为,你可以方便地调用,类似 Java 中的把复杂的逻辑封装为代码

  • 优点
    • 提高性能:存储过程在数据库服务器上执行,减少了通信次数
    • 安全:存储过程封装好了操作,应用程序只需要传入参数不执行 SQL,执行 SQL 交给数据库服务器的存储过程来执行,防止 SQL 注入
  • 缺点
    • 存储过程不可移植
    • 编写起来更加复杂

https://www.runoob.com/w3cnote/mysql-stored-procedure.html

存储过程的主要用途:

  1. 复杂逻辑处理: 存储过程可以包含复杂的业务逻辑和控制流程,例如条件判断、循环、异常处理等,从而减少在应用程序中处理这些逻辑的复杂性。
  2. 减少网络流量: 将一组 SQL 语句打包在一个存储过程中,可以减少应用程序和数据库之间的数据传输量,从而提高整体性能

游标