Mysql——约束与多表查询
一、约束
1.1定义
约束是对表中的数据进行限制的一套规则,用于防止用户向数据库中输入无效数据。它可以保证表中的数据满足特定业务规则和逻辑,从而维护数据的准确性和可靠性。
1.2作用
-
数据完整性 :约束可以确保数据在插入、更新或删除时符合预定义的规则,从而避免数据不一致和错误。
-
数据质量 :通过约束,可以强制执行数据的格式、范围和相关性等要求,从而提高数据的质量。
-
优化查询 :约束可以提供有关数据结构和关系的信息,有助于优化数据库查询的性能,使数据库管理系统能够更有效地执行查询操作。
1.3常见的约束及其作用
约束 | 描述 | 关键字 |
非空约束 | 限制该字段的数据不能为null | NOT NULL |
唯一约束 | 保证该字段数据都是唯一的、不重复的 | UNIQUE |
主键约束 | 主键是一行数据的唯一标识,要求非空且唯一 | PRIMARY KEY |
默认约束 | 保存数据时,如果未指定该字段的值,则采用默认值 | DEFAULT |
检查约束 | 保证字段值满足一个条件 | CHECK |
外键约束 | 用来让两张表的数据之间建立连接,保证数据的一致性和完整性 | FOREIGN KEY |
非空约束
CREATE TABLE products (
product_id INT PRIMARY KEY,
product_name VARCHAR(50) NOT NULL, -- 非空约束
price DECIMAL(10, 2) NOT NULL, -- 非空约束
description TEXT
);
唯一约束
CREATE TABLE users (
user_id INT PRIMARY KEY,
username VARCHAR(50) NOT NULL UNIQUE, -- 唯一约束
email VARCHAR(100) UNIQUE -- 唯一约束
);
主键约束
CREATE TABLE employees (
employee_id INT PRIMARY KEY, -- 主键约束
name VARCHAR(50) NOT NULL,
position VARCHAR(50),
salary DECIMAL(10, 2)
);
默认约束
CREATE TABLE blog_posts (
post_id INT PRIMARY KEY,
title VARCHAR(100) NOT NULL,
content TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP -- 默认值约束
);
如果没有指定created_at,将自动使用当前时间戳。
检查约束
CREATE TABLE orders (
order_id INT PRIMARY KEY,
customer_id INT NOT NULL,
order_date DATE NOT NULL,
status VARCHAR(20) CHECK (status IN ('Processing', 'Shipped', 'Delivered')) -- 检查约束
);
外键约束
CREATE TABLE departments (
department_id INT PRIMARY KEY, -- 主键
department_name VARCHAR(50) NOT NULL
);
CREATE TABLE employees (
employee_id INT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
department_id INT,
FOREIGN KEY (department_id) REFERENCES departments(department_id) -- 外键约束
);
添加外键
create table 表明{
字段名 数据类型,
...
[constraint] [外键名称] foreign key [外键字段名] references 主表(主表列名)
};
alter table 表名 add constraint 外键名称 foreign key [外键字段名] references 主表(主表列名);
删除外键
alter table 表名 drop foreign key 外键名称;
外键行为
行为 | 说明 |
NO ACTION | 当在父表中删除或者更新对应记录时,若有外键则不允许删除或更新 |
RESTRICT | 当在父表中删除或者更新对应记录时,若有外键则不允许删除或更新 |
CASCADE | 当在父表中删除或者更新对应记录时,若有外键则删除或更新外键在子表中的记录 |
SET NULL | 当在父表中删除对应记录时,若有外键则设置子表中该外键值为null(要求可以取null) |
SET DEFAULT | 父表变更时,子表将外键列设置为一个默认的值 |
二、多表查询
2.1什么是多表查询
多表查询是指在同一个SQL语句中,从两个或多个表中检索数据。在数据库设计中,数据通常被存储在不同的表中,以避免数据冗余并提高数据完整性。通过多表查询,可以将这些表中的相关数据组合起来,以获取有意义的结果。
2.2单表查询与多表查询的区别
-
单表查询:只涉及一个表的数据,通过WHERE子句过滤条件来查找数据。
-
多表查询:涉及两个或多个表的数据,需要使用联接(JOIN)操作来指定表之间的关系,并通过WHERE子句过滤条件来查找数据。
2.3连接类型
1. 内联接(INNER JOIN)
内联接是默认的联接类型,它返回两个表中满足连接条件的记录。
- 隐式内联接:
select 字段列表 from 表1,表2 where 条件...;
- 显示内联接 :
select 字段列表 from 表1 [inner] join 表2 on 连接条件...;
2. 外联接(OUTER JOIN)
外联接可以分为以下三种类型:
-
左外联接(LEFT OUTER JOIN):返回左表中的所有记录,以及右表中满足条件的记录。如果右表中没有匹配的记录,则返回NULL。
select 字段列表 from 表1 left [outer] join 表二 on 条件...;
-
右外联接(RIGHT OUTER JOIN):返回右表中的所有记录,以及左表中满足条件的记录。如果左表中没有匹配的记录,则返回NULL。
select 字段列表 from 表1 right [outer] join 表二 on 条件...;
-
全外联接(FULL OUTER JOIN):返回两个表中的所有记录,如果另一个表中没有匹配的记录,则返回NULL。
3. 交叉联接(CROSS JOIN)
交叉联接返回两个表的笛卡尔积,即所有可能的组合。
4. 自联接(SELF JOIN)
自联接是指将一个表与其自身进行联接。通常用于层次结构数据,例如员工表中的上下级关系,必须使用别名。
select 字段列表 from 表A 别名A join 表A 别名B on 条件...;
5.联接运算符
在SQL中,可以使用以下运算符来指定联接类型:
-
=
:用于等值联接。 -
<
、>
、<=
、>=
、<>
等用于不等值联接。
2.4实例
这里假设有三张表,一张订单表Orders,一张产品表Products,一张客户表Customers。
等值内联接
查询所有订单及其对应的产品信息:
SELECT Orders.OrderID, Orders.CustomerName, Products.ProductName
FROM Orders
INNER JOIN Products ON Orders.ProductID = Products.ProductID;
左外联接
查询所有客户及其订单信息,即使某些客户没有下过订单:
SELECT Customers.CustomerName, Orders.OrderID
FROM Customers
LEFT JOIN Orders ON Customers.CustomerID = Orders.CustomerID;
全外联接
查询所有客户和所有订单,无论是客户是否有订单,还是订单是否有客户:
SELECT Customers.CustomerName, Orders.OrderID
FROM Customers
FULL OUTER JOIN Orders ON Customers.CustomerID = Orders.CustomerID;
三、子查询
3.1什么是子查询
子查询是指嵌套在另一个SQL语句中的查询。它通常出现在SELECT、FROM、WHERE等子句中,主要用于为外部查询提供数据或条件。
3.2子查询的功能
-
条件过滤:在外查询的WHERE子句中使用子查询,根据子查询返回的结果来过滤外部查询的数据。
-
数据集:在
FROM
子句中使用子查询,将子查询的结果作为一个临时表来使用。 -
赋值:在SET和WHERE子句中使用子查询,将子查询的结果赋给变量或用于更新条件。
3.3子查询语法
SELECT column1, column2, ...
FROM table_name
WHERE column_name operator (SELECT column_name FROM table_name WHERE condition);
3.4子查询类型
-
单行子查询:子查询返回单个值。
-
多行子查询:子查询返回多个值,通常与IN、ANY、ALL等一起使用。
3.5示例
条件过滤
找到价格高于产品A的所有产品:
SELECT ProductName, Price
FROM Products
WHERE Price > (SELECT Price FROM Products WHERE ProductName = '产品A');
临时表
展示某个月份的销售数据:
SELECT s1.ProductID, s1.TotalSales
FROM (
SELECT ProductID, SUM(SalesAmount) AS TotalSales
FROM Sales
WHERE MONTH(SaleDate) = 10
GROUP BY ProductID
) s1
WHERE s1.TotalSales > 1000;
赋值
根据子查询结果更新员工的津贴:
UPDATE Employees
SET Bonus = (
SELECT AVG(PerformanceScore)
FROM Department
WHERE DepartmentID = Employees.DepartmentID
)
WHERE EmployeeID = 1001;