掌握关系数据库设计:综合指南

2025-05-25

掌握关系数据库设计:综合指南

介绍

在当今数据驱动的世界中,高效地存储和管理信息对于各种规模的企业和组织都至关重要。关系数据库已成为一种强大的解决方案,能够以结构化和可扩展的方式组织和操作数据。在本篇博文中,我们将探讨关系数据库的基础知识、其管理系统以及有效数据库设计的基础原则。


什么是数据库?

数据库是结构化的数据集合,其组织和存储方式便于高效检索、操作和管理。您可以将其想象成一个数字文件柜,里面没有实体文件夹和文档,而是整齐有序的表格和记录,方便您轻松访问。

什么是关系数据库?

关系数据库是一种将数据组织成表(关系)的数据库,表由行(记录)和列(字段)组成。这些表通过关系相互连接,从而允许以各种方式访问​​和组合数据。想象一下一组电子表格,每个表格代表数据的不同方面,但能够无缝地链接和组合它们之间的信息。

关系数据库管理系统

关系数据库管理系统 (RDBMS) 是一种用于创建、管理和与关系数据库交互的软件应用程序。它提供了一个结构化的框架,用于在数据库中存储、检索和操作数据。一些常见的 RDBMS 包括 MySQL、PostgreSQL、Oracle 和 Microsoft SQL Server。


SQL简介

SQL(结构化查询语言)是用于与关系数据库交互的标准编程语言。它允许您在数据库中创建、读取、更新和删除数据,以及定义和修改数据库结构本身。SQL 就像一种通用语言,使您能够与不同的 RDBMS 平台进行通信。

命名约定

在 SQL 中,遵循一致的命名约定对于清晰度和可维护性至关重要。以下是一个例子:

-- Good naming conventions
CREATE TABLE customers (
   customer_id INT PRIMARY KEY,
   first_name VARCHAR(100),
   last_name VARCHAR(100),
   email VARCHAR(100)
);
Enter fullscreen mode Exit fullscreen mode

什么是数据库设计?

数据库设计是创建高效且有序的结构来存储和管理数据库中数据的过程。它涉及定义表、列、关系和约束,以确保数据完整性、最小化冗余并优化性能。正确的数据库设计是构建健壮且可扩展的应用程序的基础。

数据库设计图像

数据完整性

数据完整性是指数据库中存储的数据的准确性、一致性和可靠性。它确保数据遵循特定的规则和约束,从而防止出现错误和不一致。数据完整性有三种类型:

  1. 实体完整性:确保表中的每一行都由主键唯一标识,并且主键不能具有空值。
  2. 参照完整性:通过确保一个表中的外键值与另一个表中的主键值匹配来维护表之间的关系。
  3. 域完整性:通过限制可存储的数据类型、格式和值范围来强制给定列的有效输入。
-- Example: Enforcing data integrity
CREATE TABLE orders (
    order_id INT PRIMARY KEY, -- Entity integrity
    customer_id INT FOREIGN KEY REFERENCES customers(customer_id), -- Referential integrity
    order_date DATE NOT NULL, -- Domain integrity
    total_amount DECIMAL(10, 2) CHECK (total_amount >= 0) -- Domain integrity
);

Enter fullscreen mode Exit fullscreen mode

数据库术语

  • :按行和列组织的相关数据的集合。
  • :表中的单个实例或条目(也称为记录或元组)。
  • :表中数据的特定特征或属性(也称为字段或属性)。
  • 主键:唯一标识表中每一行的列或列的组合。
  • 外键:引用另一个表的主键的列或列的组合,建立两个表之间的关系。
  • 连接:根据相关列组合两个或多个表中的行的操作。
  • 索引:一种数据结构,通过在表中创建数据的排序表示来提高数据检索操作的性能。
  • 视图:从一个或多个基础表动态生成的虚拟表。
  • 存储过程:可以作为单个单元执行的预编译的 SQL 语句集合。
  • 触发器:一种特殊类型的存储过程,当表中发生特定事件时自动执行,例如 INSERT、UPDATE 或 DELETE 语句。

原子值

在数据库设计中,存储原子值非常重要,这意味着存储无法进一步分割的最小信息片段。此原则有助于维护数据完整性并避免冗余。

例如,与其将客户的全名存储在一列中,不如将其分成名字和姓氏两列。这样,您可以轻松地分别搜索、排序或操作姓名的每个部分。

-- Example: Storing atomic values
CREATE TABLE customers (
    customer_id INT PRIMARY KEY,
    first_name VARCHAR(50),
    last_name VARCHAR(50),
    email VARCHAR(100)
);

Enter fullscreen mode Exit fullscreen mode

按键介绍

键是数据库设计中必不可少的组件,有助于确保数据完整性并建立表之间的关系。它们作为记录的唯一标识符,可实现高效的数据检索和操作。

主键索引

主键是唯一标识表中每条记录的一列或多列组合。它确保每条记录都是唯一的,并且易于定位。主键通常会被索引,以提高查询性能。

CREATE TABLE customers (
    customer_id INT PRIMARY KEY,
    first_name VARCHAR(50),
    last_name VARCHAR(50),
    email VARCHAR(100)
);

Enter fullscreen mode Exit fullscreen mode

查找表

查找表(也称为引用表或代码表)是包含预定义值集的表,这些值集可用于填充其他表中的列。查找表通过确保一致性和减少冗余来帮助维护数据完整性。

-- Lookup table for product categories
CREATE TABLE product_categories (
    category_id INT PRIMARY KEY,
    category_name VARCHAR(100)
);

-- Products table referencing the lookup table
CREATE TABLE products (
    product_id INT PRIMARY KEY,
    product_name VARCHAR(100),
    category_id INT,
    FOREIGN KEY (category_id) REFERENCES product_categories(category_id)
);

Enter fullscreen mode Exit fullscreen mode

超级键和候选键

超键是表中用于唯一标识每条记录的一个或多个列的集合。候选键是最小超键,这意味着它不包含任何不必要的列。换句话说,候选键是具有唯一标识每条记录所需的最少列数的超键。

主键和备用键

主键是被选为表的主要唯一标识符的候选键。备用键(也称为唯一键)是指任何其他可以被选为主键但最终未被选为主键的候选键。

CREATE TABLE employees (
    employee_id INT PRIMARY KEY,
    email VARCHAR(100) UNIQUE, -- Alternate key
    first_name VARCHAR(50),
    last_name VARCHAR(50)
);
Enter fullscreen mode Exit fullscreen mode

代理键和自然键

代理键是一种人工生成的键(通常是序列号或 GUID),用作表中的主键。它与数据本身没有任何内在含义或关系。而自然键则是从数据本身派生出来的键,例如员工 ID 或产品代码。

-- Surrogate key
CREATE TABLE orders (
    order_id INT PRIMARY KEY IDENTITY(1,1), -- Surrogate key
    customer_name VARCHAR(100),
    order_date DATE
);

-- Natural key
CREATE TABLE products (
    product_code VARCHAR(10) PRIMARY KEY, -- Natural key
    product_name VARCHAR(100),
    price DECIMAL(10,2)
);
Enter fullscreen mode Exit fullscreen mode

我应该使用代理键还是自然键?

代理键和自然键之间的选择取决于几个因素,包括数据的性质、数据发生变化的可能性以及重复或冲突的可能性。

代理键通常是首选,因为它们具有以下特点:

  • 不可变:即使数据发生变化,它们也不会随着时间而改变。
  • 保证唯一:由数据库系统生成,确保唯一性。
  • 不透明:它们不会透露有关数据本身的任何信息,这有利于安全和隐私。

另一方面,自然键在以下情况下会很有优势:

  • 数据具有固有的唯一性,例如产品代码或员工 ID。
  • 数据不太可能随着时间的推移而发生变化,从而降低了冲突或重复的风险。
  • 需要人类可读且有意义的标识符。

外键

外键是某个表中引用另一个表主键的一列或多列组合。它建立两个表之间的联系,并强制执行引用完整性,确保子表中的数据有效且与父表中的数据一致。

CREATE TABLE orders (
    order_id INT PRIMARY KEY,
    customer_id INT,
    order_date DATE,
    FOREIGN KEY (customer_id) REFERENCES customers(customer_id)
);

Enter fullscreen mode Exit fullscreen mode

非空外键

在某些情况下,可能需要在外键列上设置 NOT NULL 约束,即该列不能为空值。此约束确保子表中的每条记录都与父表中的有效记录相关联。

CREATE TABLE orders (
    order_id INT PRIMARY KEY,
    customer_id INT NOT NULL,
    order_date DATE,
    FOREIGN KEY (customer_id) REFERENCES customers(customer_id)
);

Enter fullscreen mode Exit fullscreen mode

外键约束

外键约束定义了表之间的引用完整性规则。这些约束可以包括在父表中的引用记录被更新或删除时要采取的操作,例如:

  • CASCADE:当父表中的记录被更新或删除时,子表中对应的记录也被更新或删除。
  • SET NULL:当父表中的记录被更新或删除时,子表中对应的外键值被设置为NULL。
  • NO ACTION:当父表中的记录被更新或删除时,子表中对应的外键值保持不变,如果违反了参照完整性,则操作回滚。
CREATE TABLE orders (
    order_id INT PRIMARY KEY,
    customer_id INT,
    order_date DATE,
    FOREIGN KEY (customer_id) REFERENCES customers(customer_id) ON UPDATE CASCADE ON DELETE SET NULL
);

Enter fullscreen mode Exit fullscreen mode

简单键、复合键、复合键

  • 简单键是用作主键或外键的单个列。
  • 复合键是用作主键或外键的两个或多个列的组合。
  • 复合键是两个或多个简单键的组合,用作外键。
-- Simple key
CREATE TABLE orders (
    order_id INT PRIMARY KEY,
    ...
);

-- Composite key
CREATE TABLE order_items (
    order_id INT,
    product_id INT,
    quantity INT,
    PRIMARY KEY (order_id, product_id)
);

-- Compound key
CREATE TABLE shipments (
    shipment_id INT PRIMARY KEY,
    order_id INT,
    product_id INT,
    FOREIGN KEY (order_id, product_id) REFERENCES order_items(order_id, product_id)
);

Enter fullscreen mode Exit fullscreen mode

关系

关系是关系数据库的基石,它允许您连接和组合来自不同表的数据。关系主要有三种类型:

关系图像

一对一关系

在一对一关系中,一个表中的每条记录都与另一个表中的一条记录精确关联,反之亦然。例如,假设一个数据库中,每个员工有且仅有一位经理,每个经理又管理且仅有一位员工。这种关系在实践中相对少见。

一对一图像

一对多关系

在一对多关系中,一个表(“一”方)中的每条记录可以与另一个表(“多”方)中的多条记录相关联。例如,在学校数据库中,一位老师可以教多个班级,但每个班级只能由一位老师授课。

一对多图像

多对多关系

在多对多关系中,一个表中的每条记录可以与另一个表中的多条记录相关联,反之亦然。例如,在一所大学的数据库中,一名学生可以注册多门课程,而每门课程也可以有多名学生注册。

多对多关系图像

关系摘要

  • 一对一:表 A 中的一条记录与表 B 中的一条且仅一条记录相关,反之亦然。
  • 一对多:表 A 中的一条记录可以与表 B 中的多条记录关联,但表 B 中的一条记录只能与表 A 中的一条记录关联。
  • 多对多:表 A 中的多条记录可以与表 B 中的多条记录相关,反之亦然。

设计关系(SQL 实现)

1 - 设计一对一关系

要设计一对一关系,您可以将两个表的所有列包含在一个表中,或者创建两个单独的表并使用外键约束来链接它们。

-- Option 1: Single table
CREATE TABLE employees (
    employee_id INT PRIMARY KEY,
    first_name VARCHAR(50),
    last_name VARCHAR(50),
    manager_first_name VARCHAR(50),
    manager_last_name VARCHAR(50)
);

-- Option 2: Two tables with foreign key
CREATE TABLE employees (
    employee_id INT PRIMARY KEY,
    first_name VARCHAR(50),
    last_name VARCHAR(50),
    manager_id INT UNIQUE,
    FOREIGN KEY (manager_id) REFERENCES employees(employee_id)
);
Enter fullscreen mode Exit fullscreen mode

2 -设计一对多关系

要设计一对多关系,通常需要创建两个表:一个父表(“一”)和一个子表(“多”。子表包含一个外键列,该列引用父表的主键。

-- Parent table
CREATE TABLE teachers (
    teacher_id INT PRIMARY KEY,
    first_name VARCHAR(50),
    last_name VARCHAR(50)
);

-- Child table
CREATE TABLE classes (
    class_id INT PRIMARY KEY,
    class_name VARCHAR(100),
    teacher_id INT,
    FOREIGN KEY (teacher_id) REFERENCES teachers(teacher_id)
);
Enter fullscreen mode Exit fullscreen mode

3 - 设计多对多关系

要设计多对多关系,通常需要创建第三个表(称为连接表或关联表),用于将两个主表连接在一起。此连接表包含引用主表的外键列

-- Table 1
CREATE TABLE students (
    student_id INT PRIMARY KEY,
    first_name VARCHAR(50),
    last_name VARCHAR(50)
);

-- Table 2
CREATE TABLE courses (
    course_id INT PRIMARY KEY,
    course_name VARCHAR(100),
    description TEXT
);

-- Junction or Intemediary table
CREATE TABLE enrollments (
    enrollment_id INT PRIMARY KEY,
    student_id INT,
    course_id INT,
    FOREIGN KEY (student_id) REFERENCES students(student_id),
    FOREIGN KEY (course_id) REFERENCES courses(course_id)
);
Enter fullscreen mode Exit fullscreen mode

父表和子表

在一对多或多对多关系中,“一”侧的表通常称为父表,而“多”侧的表称为子表。子表包含一个外键,该外键引用父表的主键。

例如,在老师与班级的关系中,teachers表是父表,表classes是子表。同样,在学生与课程的关系中,studentscourses表是父表,而enrollm

实体关系建模简介

实体关系模型 (ER 模型) 是一种用于数据库设计的技术,用于直观地表示数据库的逻辑结构。它有助于识别实体(表)、属性(列)及其之间的关系,从而使数据库设计更易于理解和沟通。

ER 图由以下组件组成:

  • 实体:用矩形表示,实体是数据库中的表或对象。
  • 属性:列在实体矩形内,属性是描述实体的列或字段。
  • 关系:关系用连接实体的线表示,描述实体之间的关联。

基数

基数定义了两个实体之间的数值关系。它指定一个实体可以与另一个实体的单个实例关联的最大实例数。最常见的基数是:

  • 一对一(1:1):实体 A 的一个实例可以与实体 B 的最多一个实例相关联,反之亦然。
  • 一对多(1:N):实体 A 的一个实例可以与实体 B 的多个实例相关联,但实体 B 的一个实例只能与实体 A 的一个实例相关联。
  • 多对多(M:N):实体 A 的多个实例可以与实体 B 的多个实例相关联,反之亦然。

在 ER 图中,基数使用特定符号表示,例如,一条线表示一对一,一条带箭头的线表示一对多,一条两端都带箭头的线表示多对多关系。

基数图像

情态

情态是指实体实例的存在是否依赖于它与另一个实体的关系。情态有两种类型:

  • 部分模态:实例的存在不依赖于它与其他实体的关系。例如,客户可以存在,即使没有任何订单。
  • 完全模态:实例的存在取决于它与其他实体的关系。例如,订单商品不能脱离订单而存在。

在 ER 图中,模态使用特定符号表示,例如单条表示部分模态,双条表示全部模态。


数据库规范化简介

数据库规范化是组织数据库中数据的过程,旨在减少冗余、最大程度地减少数据异常(插入、更新和删除异常)并提高数据完整性。它涉及将数据库分解为更小的表,并根据特定规则或范式定义它们之间的关系。

数据库规范化的主要目标是:

  • 消除冗余数据
  • 确保数据完整性
  • 促进数据操作和维护

数据库规范化中有几种范式,每种范式都建立在前一种范式的基础上。最常用的范式是:

  1. 第一范式(1NF)
  2. 第二范式(2NF)
  3. 第三范式(3NF)

1NF(数据库规范化的第一范式)

第一范式 (1NF) 是范式的最基本形式。它规定表中的属性(列)必须具有原子值,这意味着表中的每个单元格都应该包含单个值,而不是一组值。

例如,假设一个表中包含一个名为“PhoneNumbers”的列,该列存储了客户的多个电话号码。这违反了第一范式 (1NF),因为该列包含一组值,而不是单个值。为了符合第一范式 (1NF),您需要将电话号码拆分成单独的列,或者为电话号码创建一个单独的表。

-- Violates 1NF
CREATE TABLE customers (
    customer_id INT PRIMARY KEY,
    name VARCHAR(100),
    phone_numbers VARCHAR(200) -- Stores multiple phone numbers, violating 1NF
);

-- Conforms to 1NF
CREATE TABLE customers (
    customer_id INT PRIMARY KEY,
    name VARCHAR(100),
    phone1 VARCHAR(20),
    phone2 VARCHAR(20),
    phone3 VARCHAR(20)
);
Enter fullscreen mode Exit fullscreen mode

2NF(数据库规范化的第二范式)

第二范式(2NF)建立在第一范式(1NF)的基础上,解决了部分依赖的问题。如果一个表符合第一范式(1NF),并且每个非主属性(列)都完全依赖于整个主键,那么该表就符合第二范式(2NF)。

换句话说,如果一个表有一个复合主键(由多个列组成),那么所有非键列都必须依赖于整个主键,而不仅仅是其中的一部分。

例如,考虑一个表,其复合主键为(student_id, course_id),列为grade。如果该grade列仅依赖于,而不依赖于course_id的组合,则该表违反了 2NF。student_idcourse_id

-- Violates 2NF
CREATE TABLE student_courses (
    student_id INT,
    course_id INT,
    course_name VARCHAR(100), -- Depends only on course_id, not the entire primary key
    grade CHAR(2), 
    PRIMARY KEY (student_id, course_id)
);

-- Conforms to 2NF
CREATE TABLE student_courses (
    student_id INT,
    course_id INT,
    grade CHAR(2),
    PRIMARY KEY (student_id, course_id)
);

CREATE TABLE courses (
    course_id INT PRIMARY KEY,
    course_name VARCHAR(100)
);
Enter fullscreen mode Exit fullscreen mode

3NF(数据库规范化的第三范式)

第三范式 (3NF) 在 2NF 的基础上,解决了传递依赖的问题。如果一个表符合 2NF,并且每个非主属性都非传递地依赖于主键,那么它就符合 3NF。

换句话说,如果非键列依赖于另一个非键列,则该表违反了 3NF,并且非键列应该分离到它们自己的表中。

例如,考虑一个包含列student_idstudent_nameclass_id和 的表class_namestudent_name列 依赖于student_idclass_name列 依赖于class_id。然而,列 也通过 传递class_name地依赖于。这违反了 3NF。student_idclass_id

-- Violates 3NF
CREATE TABLE student_classes (
    student_id INT,
    student_name VARCHAR(100),
    class_id INT,
    class_name VARCHAR(100),
    PRIMARY KEY (student_id, class_id)
);

-- Conforms to 3NF
CREATE TABLE students (
    student_id INT PRIMARY KEY,
    student_name VARCHAR(100)
);

CREATE TABLE classes (
    class_id INT PRIMARY KEY,
    class_name VARCHAR(100)
);

CREATE TABLE student_classes (
    student_id INT,
    class_id INT,
    PRIMARY KEY (student_id, class_id),
    FOREIGN KEY (student_id) REFERENCES students(student_id),
    FOREIGN KEY (class_id) REFERENCES classes(class_id)
);
Enter fullscreen mode Exit fullscreen mode

通过遵循数据库规范化的原则,您可以创建结构良好且高效的数据库,以最大限度地减少冗余、维护数据完整性并促进数据操作和维护。


索引(聚集索引、非聚集索引、复合索引)

索引是一种数据结构,可以提高数据库中数据检索操作的性能。它们在表中创建数据的排序表示,从而实现更快的搜索和查询。索引有以下几种类型:

  • 聚集索引:聚集索引根据索引键值对表中的行进行物理重新排序。每个表只能有一个聚集索引。
  • 非聚集索引:非聚集索引是一个单独的对象,包含索引键值和指向表中相应行的指针。一个表可以有多个非聚集索引。
  • 复合索引:复合索引是索引键中包含多个列的索引。它可以是聚集索引,也可以是非聚集索引。
-- Clustered index
CREATE CLUSTERED INDEX idx_customers_name
ON customers (last_name, first_name);

-- Nonclustered index
CREATE NONCLUSTERED INDEX idx_orders_date
ON orders (order_date);

-- Composite index
CREATE INDEX idx_products_category_price
ON products (category_id, price);
Enter fullscreen mode Exit fullscreen mode

数据类型

在数据库的世界里,数据类型就像容纳特定类型信息的不同形状的容器。就像你不会把液体放在篮子里,也不会把固体放在罐子里一样,数据库需要强制使用特定的数据类型,以确保数据的完整性和一致性。

SQL 中的一些常见数据类型包括:

  • INTor INTEGER:存储整数,如4217
  • FLOATor DOUBLE:存储十进制数,如3.14159or 0.00005
  • VARCHARTEXT:存储文本数据,如名称或描述。
  • DATEor DATETIME:存储日期和时间值,如'2023-05-06'or '2024-01-01 12:34:56'
  • BOOLEAN:存储真/假值,如1(true) 或0(false)。

选择正确的数据类型至关重要,因为它会影响数据的存储、查询和操作方式。例如,尝试在INT列中存储较大的字符串可能会导致错误或数据截断。

CREATE TABLE users (
    id INT PRIMARY KEY,
    name VARCHAR(50) NOT NULL,
    age INT,
    is_active BOOLEAN DEFAULT 1
);

Enter fullscreen mode Exit fullscreen mode

在这个例子中,我们创建一个users表,其列为id(整数)、name(最多 50 个字符的字符串)、age(整数)和is_active(布尔值,默认值为1或 true)。


连接简介

连接就像连接数据库中不同表的桥梁,允许您组合和检索来自多个来源的相关数据。它们是关系数据库中的基本概念,对于高效查询和操作数据至关重要。

连接图像

内连接

内连接就像两个表之间的友好握手,只有两个表中值匹配的行才会包含在结果集中。它是一种基于一个或一组公共列来合并多个表中数据的方法。

SELECT users.name, orders.order_date
FROM users
INNER JOIN orders ON users.id = orders.user_id;
Enter fullscreen mode Exit fullscreen mode

在这个例子中,我们nameusers表中检索列并order_dateorders表中检索列,但仅限于id表中与表users匹配的行user_idorders

3 个表的内连接(示例)

假设我们有三张表:usersordersproducts。我们想要检索每个订单的用户姓名、订单日期和产品名称。我们可以通过在这三张表之间执行内连接来实现:

SELECT users.name, orders.order_date, products.product_name
FROM users
INNER JOIN orders ON users.id = orders.user_id
INNER JOIN products ON orders.product_id = products.id;
Enter fullscreen mode Exit fullscreen mode

这里,我们首先根据 和 列连接usersorders然后,我们将连接的结果与和列的表连接起来。这样,我们就可以在单个查询中检索所有三个表中的数据,但仅限于满足连接条件的行。iduser_idproductsproduct_idid

外连接简介

内连接就像友好的握手,而外连接更像是热情的拥抱。它们不仅包含两个表中匹配的行,还包含一个或两个表中不匹配的行,具体取决于外连接的类型。

右外连接

右外连接就像右表对左表的热情拥抱。它包含右表的所有行以及左表中匹配的行。如果左表中没有匹配的行,则结果将包含NULL左表列的值。

SELECT users.name, orders.order_date
FROM users
RIGHT OUTER JOIN orders ON users.id = orders.user_id;
Enter fullscreen mode Exit fullscreen mode

orders在此示例中,我们从表(右表)中检索所有行,并nameusers表(左表)中检索匹配的值。如果订单没有匹配的用户,则该name列将包含NULL

带有 NOT NULL 列的 JOIN

有时,您可能希望仅对非空列执行连接。当您想从结果集中排除包含缺失数据的行时,这会很有用。

SELECT users.name, orders.order_date
FROM users
INNER JOIN orders ON users.id = orders.user_id AND users.name IS NOT NULL;

Enter fullscreen mode Exit fullscreen mode

users在这个例子中,我们在和表之间执行内连接orders,但我们添加了一个附加条件,以确保结果集中users.name IS NOT NULL只包含非空值的行。name

跨 3 个表的外连接

与内连接示例类似,我们可以跨多个表执行外连接。假设我们想要检索所有订单,以及用户姓名和产品名称,即使usersproducts表中存在缺失值。

SELECT users.name, orders.order_date, products.product_name
FROM orders
LEFT OUTER JOIN users ON orders.user_id = users.id
LEFT OUTER JOIN products ON orders.product_id = products.id;

Enter fullscreen mode Exit fullscreen mode

这里,我们从orders表开​​始,并对 和users表执行左外连接。这确保所有订单都包含在结果集中,以及匹配的用户名和产品名称(如果有)。如果或表products中没有匹配的行,则相应的列将包含值。usersproductsNULL

别名

别名就像 SQL 查询中表或列的昵称。它们可以使查询更具可读性和更容易理解,尤其是在处理较长的表名或列名,或者在查询中多次引用同一张表时。

SELECT u.name, o.order_date, p.product_name
FROM users u
INNER JOIN orders o ON u.id = o.user_id
INNER JOIN products p ON o.product_id = p.id;

Enter fullscreen mode Exit fullscreen mode

u在此示例中,我们使用了表的别名users、表o的别名orders以及p表的别名products。这使得查询更简洁、更易于阅读,而无需多次重复完整的表名。

自连接

自连接就像一张表在与自己对话。它是一种基于特定条件或同一张表内的关系,将一个表与其自身连接起来的方法。在处理分层或递归数据结构(例如员工-经理关系或嵌套类别)时,这种方法非常有用。

SELECT e.name AS employee, m.name AS manager
FROM employees e
LEFT OUTER JOIN employees m ON e.manager_id = m.id;
Enter fullscreen mode Exit fullscreen mode

在此示例中,我们对表执行自连接employees,以检索每位员工的姓名及其对应经理的姓名。我们使用左外连接来确保所有员工都包含在结果集中,即使他们没有分配经理。


数据库标记语言 (DBML)

数据库建模语言 (DBML) 是一种简单直观的标记语言,用于描述关系数据库的结构。它提供了一种人类可读的方式来定义表、列、关系和约束,从而简化了数据库设计方面的沟通和协作。

DBML 入门

要开始使用 DBML,您需要一个文本编辑器,并对数据库概念有基本的了解。让我们创建第一个 DBML 文件:

// my_database.dbml

Table users {
  id int [pk, increment]
  username varchar
  email varchar [unique]
  created_at datetime [default: `now()`]
}

Enter fullscreen mode Exit fullscreen mode

在此示例中,我们定义了一个users包含idusernameemail和 列的表created_at[pk]标签指定id为主键,[increment]表示自动递增,[unique]确保 的唯一性email[default:now()]将 的默认值设置created_at为当前时间戳。

创建表

DBML 允许您在单个文件中定义多个表及其列。让我们向数据库添加更多表:

// my_database.dbml

Table users {
  id int [pk, increment]
  username varchar
  email varchar [unique]
  created_at datetime [default: `now()`]
}

Table posts {
  id int [pk, increment]
  title varchar
  content text
  user_id int [ref: > users.id]
  created_at datetime [default: `now()`]
}

Enter fullscreen mode Exit fullscreen mode

在此示例中,我们添加了一个表,其中包含和 的posts。标签在表中的列和表中的列之间建立了外键关系idtitlecontentuser_idcreated_at[ref: > users.id]user_idpostsidusers

定义关系

DBML 支持表之间的各种关系,包括一对一、一对多和多对多。让我们在数据库中定义一些关系:

// my_database.dbml

Table users {
  id int [pk, increment]
  username varchar
  email varchar [unique]
  created_at datetime [default: `now()`]
}

Table posts {
  id int [pk, increment]
  title varchar
  content text
  user_id int [ref: > users.id]
  created_at datetime [default: `now()`]
}

Ref: users.id < posts.user_id

Enter fullscreen mode Exit fullscreen mode

users在这个例子中,我们定义了和表之间的一对多关系posts。该Ref: users.id < posts.user_id行指定表id中的列被表中的列users引用user_idposts

添加约束

约束确保数据完整性并在数据库上强制执行规则。DBML 支持各种约束,例如主键、外键、唯一约束和默认值。让我们向表添加一些约束:

// my_database.dbml

Table users {
  id int [pk, increment]
  username varchar [unique]
  email varchar [unique]
  created_at datetime [default: `now()`]
}

Table posts {
  id int [pk, increment]
  title varchar
  content text
  user_id int [ref: > users.id]
  created_at datetime [default: `now()`]
}

Ref: users.id < posts.user_id

Enter fullscreen mode Exit fullscreen mode

在这个更新的例子中,我们向表中的列添加了一个[unique]约束,以确保每个用户名都是唯一的。usernameusers

记录您的数据库

DBML 允许您向数据库架构添加注释和注解,使其更易于理解和维护。让我们用注释来记录我们的表:

// my_database.dbml

Table users {
  id int [pk, increment] // Unique identifier for users
  username varchar [unique] // User's username
  email varchar [unique] // User's email address
  created_at datetime [default: `now()`] // Date and time when the user was created
}

Table posts {
  id int [pk, increment] // Unique identifier for posts
  title varchar // Title of the post
  content text // Content of the post
  user_id int [ref: > users.id] // ID of the user who created the post
  created_at datetime [default: `now()`] // Date and time when the post was created
}

Ref: users.id < posts.user_id // Relationship between users and posts

Enter fullscreen mode Exit fullscreen mode

DBML 的优势

  • 简单且人类可读的语法
  • 数据库无关方法
  • dbdiagram.io上的免费可视化工具
  • 一致的可读性和可维护性约定
  • 丰富的文档和示例

结论

总而言之,关系数据库设计是现代应用程序中高效数据组织的支柱。理解其原理将助您创建强大且可扩展的数据库。接下来,我们将深入探讨 SQL 语法,释放与数据库高效交互的潜能。敬请期待我们对 SQL 世界的探索!

文章来源:https://dev.to/louaiboumediene/mastering-relational-database-design-a-compressive-guide-3jh8
PREV
这些是 2021 年最有趣的前端开发工具吗?
NEXT
VS Code + GitHub Gist = 开发者微博(又名“GistLog”)