MySQL三大范式查询详解(mysql 三大范式查询)
MySQL三大范式查询详解
在关系型数据库中,三大范式是非常重要的概念,它可以保证数据库的数据结构设计合理、高效。本文将详细讲解三大范式及在MySQL数据库中的实现,并提供查询示例。
一、第一范式(1NF)
第一范式要求数据表中的所有列都是不可分割的原子值,也就是每个列都应该只包含一个单一的数据类型(如整型、浮点型等),而不是包含多个数据。这个实务表包括下列数据项:OrderNumber、Date、CustomerName、Address、ItemNumber、Description、Price。这样的表不符合第一范式,因为它的内容不是原子性的。
+————-+————+—————-+———————+————+————-+——-+
| OrderNumber | Date | CustomerName | Address | ItemNumber | Description | Price |
+————-+————+—————-+———————+————+————-+——-+
| 00123 | 2020-03-01 | John Smith | 123 Maple Street | 137 | Widget | 12.95 |
| 00123 | 2020-03-01 | John Smith | 123 Maple Street | 140 | Gadget | 28.95 |
| 00201 | 2020-03-02 | Jane Doe | 456 Oak Street | 137 | Widget | 12.95 |
| 00201 | 2020-03-02 | Jane Doe | 456 Oak Street | 141 | Gizmo | 23.95 |
| 00315 | 2020-03-02 | Sam Johnson | 789 Elm Street | 140 | Gadget | 28.95 |
| 00315 | 2020-03-02 | Sam Johnson | 789 Elm Street | 137 | Widget | 12.95 |
| 00315 | 2020-03-02 | Sam Johnson | 789 Elm Street | 141 | Gizmo | 23.95 |
| 00430 | 2020-03-03 | Susan Williams | 101 Pine Street | 137 | Widget | 12.95 |
| 00430 | 2020-03-03 | Susan Williams | 101 Pine Street | 140 | Gadget | 28.95 |
| 00582 | 2020-03-04 | Jack Brown | 314 Walnut Street | 140 | Gadget | 28.95 |
| 00582 | 2020-03-04 | Jack Brown | 314 Walnut Street | 137 | Widget | 12.95 |
| 00582 | 2020-03-04 | Jack Brown | 314 Walnut Street | 141 | Gizmo | 23.95 |
+————-+————+—————-+———————+————+————-+——-+
我们可以将数据分为两个表,购买订单表(Orders)和订单条目表(OrderItems):
Orders:
+————-+————+—————-+———————+
| OrderNumber | Date | CustomerName | Address |
+————-+————+—————-+———————+
| 00123 | 2020-03-01 | John Smith | 123 Maple Street |
| 00201 | 2020-03-02 | Jane Doe | 456 Oak Street |
| 00315 | 2020-03-02 | Sam Johnson | 789 Elm Street |
| 00430 | 2020-03-03 | Susan Williams | 101 Pine Street |
| 00582 | 2020-03-04 | Jack Brown | 314 Walnut Street |
+————-+————+—————-+———————+
OrderItems:
+————-+————+————-+——-+
| OrderNumber | ItemNumber | Description | Price |
+————-+————+————-+——-+
| 00123 | 137 | Widget | 12.95 |
| 00123 | 140 | Gadget | 28.95 |
| 00201 | 137 | Widget | 12.95 |
| 00201 | 141 | Gizmo | 23.95 |
| 00315 | 140 | Gadget | 28.95 |
| 00315 | 137 | Widget | 12.95 |
| 00315 | 141 | Gizmo | 23.95 |
| 00430 | 137 | Widget | 12.95 |
| 00430 | 140 | Gadget | 28.95 |
| 00582 | 140 | Gadget | 28.95 |
| 00582 | 137 | Widget | 12.95 |
| 00582 | 141 | Gizmo | 23.95 |
+————-+————+————-+——-+
二、第二范式(2NF)
第二范式要求在满足第一范式的前提下,非主键列必须依赖于主键,而不能部分依赖主键。
举个例子,我们创建一个员工(Employees)表,包括以下数据项:
+———+————-+———-+————-+
| EmpID | FirstName | LastName | DeptID |
+———+————-+———-+————-+
| 100 | John | Smith | 1 |
| 101 | Jane | Doe | 2 |
| 102 | Sam | Johnson | 1 |
+———+————-+———-+————-+
出于数据结构设计的考虑,这里我们仅保留了DeptID的编号,通过外键关联到另一个表Deptartment中获取其他部门信息:
+———+———–+————+
| DeptID | DeptName | DeptHead |
+———+———–+————+
| 1 | IT | John Smith |
| 2 | Finance | Jane Doe |
+———+———–+————+
三、第三范式(3NF)
第三范式要求在满足第一、第二范式的前提下,非主键列之间不能存在传递依赖关系。这个规则被描述为“每个非主属性都必须直接依赖于主键,不能对其他非主属性产生传递依赖”。
对于订单模型,我们已经将其拆成了两个表,Orders和OrderItems,但仍然存在一些问题。比如,如果我们将Product表中的Description列移至OrderItems表,那么Description列将既依赖于Product表的主键ProductID,又依赖于OrderItems表的主键OrderNumber和ItemNumber,这就违反了第三范式。
为了避免这种情况,我们需要创建一个新的Product表,其中包含描述信息和价格:
+————+————-+
| ItemNumber | Price |
+————+————-+
| 137 | 12.95 |
| 140 | 28.95 |
| 141 | 23.95 |
+————+————-+
OrderItems表则只需包含三个数据项:OrderNumber、ItemNumber和数量(Quantity):
+————-+————+———-+
| OrderNumber | ItemNumber | Quantity |
+————-+————+———-+
| 00123 | 137 | 1 |
| 00123 | 140 | 1 |
| 00201 | 137 | 1 |
| 00201 | 141 | 1 |
| 00315 | 140 | 1 |
| 00315 | 137 | 1 |
| 00315 | 141 | 1 |
| 00430 | 137 | 1 |
| 00430 | 140 | 1 |
| 00582 | 140 | 1 |
| 00582 | 137 | 1 |
| 00582 | 141 | 1 |
+————-+————+———-+
在这种情况下,我们可以通过JOIN操作连接这三个表来查询订单草稿的详细信息。例如,如果我们想获得订单数量大于1的产品列表:
SELECT Product.Description, SUM(OrderItems.Quantity) AS TotalQuantity
FROM Orders
JOIN OrderItems ON Orders.OrderNumber = OrderItems.OrderNumber
JOIN Product ON OrderItems.ItemNumber = Product.ItemNumber
GROUP BY Product.Description
HAVING SUM(OrderItems.Quantity) > 1;
以上查询可以通过联结三个表来获取数据。我们将Order表联接到OrderItems表的OrderNumber列,然后将OrderItems表联接到Product表的ItemNumber列,以便获取每个产品的描述信息和价格。我们按产品描述进行汇总,并选择数量大于1的产品。