使用场景:当且仅当你只想返回多个表中匹配的行
语法1:
SELECT * FROM table1 INNER JOIN table2 ON table1.column = table2.column;
语法2:
SELECT * FROM table1,table2 WHERE table1.column = table2.column;
语法3:
SELECT * FROM table1 JOIN table2 ON table1.column = table2.column;
(1)查询会对 table1
的每一行的 column
值依次和 table2
的每一行的 column
值进行比较
(2)table1
的每一行的column可能在table2中找到一条/多条/没有column相等的数据,找到几条,那一行的查询结果就是几条
(3)注意:如果table1的某一行没有在table2中找到column
相等的值,那么查询结果中是不会有那一行的数据的
+----+----------+
| ID | Username |
+----+----------+
| 1 | Alice |
| 2 | Bob |
| 3 | Charlie |
+----+----------+
表: orders
+---------+---------+
| OrderID | UserID |
+---------+---------+
| 101 | 1 |
| 102 | 1 |
| 103 | 2 |
| 104 | 5 |
+---------+---------+
SELECT users.ID, users.Username, orders.OrderID
FROM users, orders
WHERE users.ID = orders.UserID;
+----+----------+---------+
| ID | Username | OrderID |
+----+----------+---------+
| 1 | Alice | 101 |
| 1 | Alice | 102 |
| 2 | Bob | 103 |
+----+----------+---------+
(1)在实际执行中,关系型数据库优化器通常会选择最有效的执行计划。
(2)推荐使用语法1的写法,逗号和 WHERE 子句的写法相对于 INNER JOIN 更为早期,可能在一些特殊情况下不被某些数据库系统完全支持或解释。
(3)在 INNER JOIN 中,连接的顺序是可以随意交换的,因为 INNER JOIN 是对称的。
(4) INNER可省略,JOIN 默认是指 INNER JOIN 。
例如:
-- 查询1
SELECT users.ID, users.Username, orders.OrderID, order_details.Product
FROM users
INNER JOIN orders ON users.ID = orders.UserID
INNER JOIN order_details ON orders.OrderID = order_details.OrderID;-- 查询2(连接条件的先后顺序交换了)
SELECT users.ID, users.Username, orders.OrderID, order_details.Product
FROM order_details
INNER JOIN orders ON order_details.OrderID = orders.OrderID
INNER JOIN users ON orders.UserID = users.ID;
使用场景:当你想返回左表中的所有行,以及右表中与左表匹配的行
SELECT * FROM table1 LEFT JOIN table2 ON table1.column = table2.column;
(1)拿左表的每一行的 column 去依次和右表的每一行的 column 对比。
(2)左表的每一行的 column 可能在右表中找到一条/多条/没有 column 相等的数据。
(3)如果左表的某一行没有在右表中找到 column 相等的值,查询结果中会有那一行的数据,但右表的列会显示为 NULL。
+------+--------+-------------+
| EmpID| Name | Department |
+------+--------+-------------+
| 1 | Alice | IT |
| 2 | Bob | HR |
| 3 | Charlie| Finance |
+------+--------+-------------+
表: departments
+-------------+--------+
| Department | Manager|
+-------------+--------+
| IT | John |
| HR | Mike |
| Sales | Sam |
+-------------+--------+
SELECT employees.Name, employees.Department, departments.Manager
FROM employees
LEFT JOIN departments ON employees.Department = departments.Department;
+--------+-------------+--------+
| Name | Department | Manager|
+--------+-------------+--------+
| Alice | IT | John |
| Bob | HR | Mike |
| Charlie| Finance | NULL |
+--------+-------------+--------+
(1)LEFT JOIN 也被称为 LEFT OUTER JOIN。
(2)LEFT JOIN 的关键点在于保留左表的所有行,即使在右表中没有匹配的行,也会显示左表的数据。
使用场景:当你想返回右表中的所有行,以及左表中与右表匹配的行
SELECT * FROM table1 RIGHT JOIN table2 ON table1.column = table2.column;
(1)拿右表的每一行的 column 去依次和左表的每一行的 column 对比。
(2)右表的每一行的 column 可能在左表中找到一条/多条/没有 column 相等的数据。
(3)如果右表的某一行没有在左表中找到 column 相等的值,查询结果中会有那一行的数据,但左表的列会显示为 NULL。
+------+--------+-------------+
| EmpID| Name | Department |
+------+--------+-------------+
| 1 | Alice | IT |
+------+--------+-------------+
表: departments
+-------------+--------+
| Department | Manager|
+-------------+--------+
| IT | John |
| IT | Sam |
| HR | Sarah |
+-------------+--------+
SELECT employees.Name, employees.Department, departments.Manager
FROM employees
RIGHT JOIN departments ON employees.Department = departments.Department;
+--------+-------------+--------+
| Name | Department | Manager|
+--------+-------------+--------+
| Alice | IT | John |
| Alice | IT | Sam |
| NULL | HR | Sarah |
+--------+-------------+--------+
(1)RIGHT JOIN 也被称为 RIGHT OUTER JOIN。
(2)RIGHT JOIN 的关键点在于保留右表的所有行,即使在左表中没有匹配的行,也会显示右表的数据。
SELECT *
,明确列出所需列原因:
(1)可以减少传输和处理的数据量,提高效率。
(2)有些数据不能被不该看到的人看到。暴露的数据越多,风险越大。
原因:
(1)可以减小存储空间的需求,还可以提高查询和索引的效率。
具体操作:
(1)使用
VARCHAR代替CHAR,
VARCHAR
可以根据实际存储的数据长度节省空间。当然,对于手机号这种是固定长度的字符类型,还是推荐使用char,此时使用char可以提供一些存储和检索的性能优势。
(2)使用数据库原生的日期和时间类型,如
DATE
,TIME
,DATETIME
,而不是存储字符串形式的日期和时间。a. 数据库原生的日期和时间类型提供了强大的数据完整性保障,防止了存储无效或不一致的日期和时间,有助于维护数据库中数据的一致性。
b. 数据库原生类型支持直接的日期和时间比较操作,轻松执行诸如"大于"、"小于"、"等于"等比较操作,而不需要进行字符串转换。这提高了查询和排序的效率。
c. 数据库通常提供了丰富的内置函数,用于处理原生日期和时间类型。这些函数包括日期加减、提取部分日期时间等,方便了对日期和时间的处理。
原因:
(1)在可能的情况下,尽量减少 JOIN 操作的数量。过多的 JOIN 可能导致性能下降。
(2)JOIN太多,会导致开发人员看得头大。
原理:先从小表中选择数据,再与大表进行连接,从而减少连接操作的数据量,提高查询性能。
例子:
users表
user_id username 1 Alice 2 Bob 3 Charlie
orders表
order_id user_id order_date total_amount 101 1 2023-01-15 50.00 102 2 2023-02-01 30.00 103 1 2023-03-10 20.00 104 3 2023-04-05 45.00 (1)
users
连接orders
SELECT xxx FROM users u JOIN orders o ON u.user_id=o.user_id WHERE u.user_id=1
执行步骤:
a. 从
users
表中选择user_id=1
的用户。这个操作涉及3次比较。b. 然后,对于从
users
中选择的每个user_id=1
,从orders
表中获取相应的行。对于从users
中选择的每一行,都需要从orders
表中获取4行。c. 总操作数:3(来自
users
表) + 1 * 4(来自orders
表)= 7次操作。
(2)orders
连接users
SELECT xxx FROM orders o JOIN users u ON o.user_id = u.user_id WHERE o.user_id=1
执行步骤:
a. 从
orders
表中选择user_id=1
的订单。这个操作涉及4次比较。b. 然后,对于从
orders
中选择的每个user_id=1
,从users
表中获取相应的用户行。对于从orders
中选择的每一行,都需要从users
表中获取3行。c. 总操作数:4(来自
orders
表) + 2 * 3(来自users
表)= 10次操作。