介绍
在当今数据驱动的世界中,高效存储和管理信息对于各种规模的企业和组织都至关重要。关系数据库已成为以结构化和可扩展的方式组织和操作数据的强大解决方案。在这篇博文中,我们将探讨关系数据库的基础知识、其管理系统以及有效数据库设计的基础原则。
什么是数据库?
数据库是结构化的数据集合,其组织和存储方式便于高效检索、操作和管理。您可以将其视为数字文件柜,其中没有物理文件夹和文档,而是整齐地组织表格和记录,方便您轻松访问。
什么是关系数据库?
关系数据库是一种将数据组织成具有行(记录)和列(字段)的表(关系)的数据库。这些表通过关系相互连接,允许以各种方式访问和组合数据。想象一下一组电子表格,每个电子表格代表数据的不同方面,但能够无缝链接和组合它们之间的信息。
关系数据库管理系统
关系数据库管理系统 (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)
);
什么是数据库设计?
数据库设计是创建高效且有组织的结构以在数据库中存储和管理数据的过程。它涉及定义表、列、关系和约束,以确保数据完整性、最大限度地减少冗余并优化性能。正确的数据库设计是构建强大且可扩展的应用程序的基础。
数据完整性
数据完整性是指数据库中存储的数据的准确性、一致性和可靠性。它确保数据遵循特定的规则和约束,防止出现错误和不一致。数据完整性有三种类型:
实体完整性:确保表中的每一行都由主键唯一标识,并且主键不能有空值。
参照完整性:通过确保一个表中的外键值与另一个表中的主键值匹配来维护表之间的关系。
域完整性:通过限制可存储的数据类型、格式和值范围来强制给定列的有效输入。
-- 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
);
数据库术语
表格:按行和列组织的相关数据的集合。
行:表中的单个实例或条目(也称为记录或元组)。
列:表中数据的特定特征或属性(也称为字段或属性)。
主键:唯一标识表中每一行的列或列的组合。
外键:引用另一个表的主键的列或列的组合,建立两个表之间的关系。
连接:根据相关列组合两个或多个表中的行的操作。
索引:一种数据结构,通过在表中创建数据的排序表示来提高数据检索操作的性能。
视图:从一个或多个基础表动态生成的虚拟表。
存储过程:可以作为单个单元执行的预编译的 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)
);
密钥简介
键是数据库设计中必不可少的组件,有助于确保数据完整性并建立表之间的关系。它们充当记录的唯一标识符,并实现高效的数据检索和操作。
主键索引
主键是唯一标识表中每条记录的一列或多列组合。它确保每条记录都是唯一的,并且可以轻松找到。主键通常会被编入索引以提高查询性能。
CREATE TABLE customers (
customer_id INT PRIMARY KEY,
first_name VARCHAR(50),
last_name VARCHAR(50),
email VARCHAR(100)
);
查找表
查找表(也称为参考表或代码表)是包含预定义值集的表,这些值集可用于填充其他表中的列。查找表通过确保一致性和减少冗余来帮助维护数据完整性。
-- 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)
);
超级密钥和候选密钥
超键是表中的一组列,用于唯一标识每条记录。候选键是最小超键,这意味着它不包含不必要的列。换句话说,候选键是具有唯一标识每条记录所需的最少列数的超键。
主键和备用键
主键是被选为表的主要唯一标识符的候选键。备用键(也称为唯一键)是任何其他可以被选为主键但未被选为主键的候选键。
CREATE TABLE employees (
employee_id INT PRIMARY KEY,
email VARCHAR(100) UNIQUE, -- Alternate key
first_name VARCHAR(50),
last_name VARCHAR(50)
);
代理键和自然键
代理键是一种人工键(通常是序列号或 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)
);
我应该使用代理键还是自然键?
代理键和自然键之间的选择取决于几个因素,包括数据的性质、数据发生变化的可能性以及重复或冲突的可能性。
代理键通常是首选,因为它们具有以下特点:
不可变:即使数据发生变化,它们也不会随着时间而改变。
保证唯一性:它们由数据库系统生成,确保唯一性。
不透明:它们不会透露有关数据本身的任何信息,这有利于安全和隐私。
另一方面,自然键在以下情况下会具有优势:
数据具有固有的唯一性,例如产品代码或员工 ID。
数据不太可能随着时间的推移而发生变化,从而降低了冲突或重复的风险。
需要人类可读且有意义的标识符。
外键
外键是某个表中引用另一个表的主键的列或列组合。它在两个表之间建立链接并强制执行引用完整性,确保子表中的数据有效且与父表中的数据一致。
CREATE TABLE orders (
order_id INT PRIMARY KEY,
customer_id INT,
order_date DATE,
FOREIGN KEY (customer_id) REFERENCES customers(customer_id)
);
NOT NULL 外键
在某些情况下,可能需要在外键列上设置 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)
);
外键约束
外键约束定义表之间的引用完整性规则。这些约束可以包括在父表中引用的记录被更新或删除时要采取的操作,例如:
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
);
简单钥匙、复合钥匙、复合钥匙
简单键是用作主键或外键的单个列。
复合键是用作主键或外键的两个或多个列的组合。
复合键是两个或多个用作外键的简单键的组合。
-- 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)
);
关系
关系是关系数据库的基石,可让您连接和组合来自不同表的数据。关系主要有三种类型:
一对一关系
在一对一关系中,一个表中的每条记录都与另一个表中的一条记录相关联,反之亦然。例如,考虑一个数据库,其中每个员工有且只有一个经理,并且每个经理只管理一个员工。这种类型的关系在实践中相对较少见。
一对多关系
在一对多关系中,一个表(“一”方)中的每个记录可以与另一个表(“多”方)中的多个记录相关联。例如,在学校的数据库中,一个老师可以教多个班级,但每个班级只能由一个老师教。
多对多关系
在多对多关系中,一个表中的每条记录可以与另一个表中的多条记录相关联,反之亦然。例如,在大学的数据库中,一名学生可以选修多门课程,每门课程也可以有多名学生选修。
关系摘要
一对一:表 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)
);
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)
);
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)
);
父表和子表
在一对多或多对多关系中,“一”方的表通常称为父表,而“多”方的表称为子表。子表包含引用父表主键的外键。
例如,在老师与班级的关系中,teachers
表是父表,表classes
是子表。同样,在学生与课程的关系中,students
和courses
表是父表,而enrollm
实体关系建模简介
实体关系建模 (ER 建模) 是数据库设计中使用的一种技术,用于直观地表示数据库的逻辑结构。它有助于识别实体(表)、属性(列)及其之间的关系,从而更易于理解和传达数据库设计。
ER 图由以下组件组成:
实体:用矩形表示,实体是数据库中的表或对象。
属性:列在实体矩形内,属性是描述实体的列或字段。
关系:关系用连接实体的线表示,描述实体之间的关联。
基数
基数定义两个实体之间的数值关系。它指定一个实体的最大实例数,该实例数可以与另一个实体的单个实例相关联。最常见的基数是:
一对一 (1:1):实体 A 的一个实例可以与实体 B 的最多一个实例相关联,反之亦然。
一对多(1:N):实体 A 的一个实例可以与实体 B 的多个实例相关联,但实体 B 的一个实例只能与实体 A 的一个实例相关联。
多对多(M:N):实体 A 的多个实例可以与实体 B 的多个实例相关联,反之亦然。
在 ER 图中,基数使用特定的符号表示,例如,一条线表示一对一,一条带箭头的线表示一对多,一条两端都有箭头的线表示多对多关系。
情态
情态是指实体实例的存在是否依赖于它与另一个实体的关系。情态有两种类型:
部分模态:实例的存在不依赖于它与其他实体的关系。例如,客户可以存在而没有任何订单。
总体模态:实例的存在取决于它与另一个实体的关系。例如,没有订单,订单项就不能存在。
在 ER 图中,模态使用特定符号表示,例如单条表示部分模态,双条表示全部模态。
数据库规范化简介
数据库规范化是组织数据库中的数据以减少冗余、最大程度减少数据异常(插入、更新和删除异常)以及提高数据完整性的过程。它涉及将数据库分解为较小的表,并根据特定规则或范式定义它们之间的关系。
数据库规范化的主要目标是:
消除冗余数据
确保数据完整性
促进数据操作和维护
数据库规范化中有几种范式,每种范式都基于前一种范式。最常用的范式是:
第一范式(1NF)
第二范式(2NF)
第三范式(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)
);
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)
);
3NF(数据库规范化的第三范式)
第三范式 (3NF) 建立在 2NF 的基础上,解决了传递依赖性问题。如果表符合 2NF,并且每个非主属性都非传递地依赖于主键,则该表符合 3NF。
换句话说,如果非关键列依赖于另一个非关键列,则该表违反 3NF,并且非关键列应该分离到它们自己的表中。
例如,考虑一个包含列student_id
、student_name
、class_id
和 的表class_name
。student_name
列 依赖于student_id
,class_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)
);
通过遵循数据库规范化的原则,您可以创建结构良好且高效的数据库,以最大限度地减少冗余、维护数据完整性并方便数据操作和维护。
索引(聚集索引、非聚集索引、复合索引)
索引是一种数据结构,可提高数据库中数据检索操作的性能。它们在表中创建数据的排序表示,从而实现更快的搜索和查询。索引有几种类型:
聚集索引:聚集索引根据索引键值对表中的行进行物理重新排序。每个表只能有一个聚集索引。
非聚集索引:非聚集索引是一个单独的对象,其中包含索引键值和指向表中相应行的指针。一个表可以有多个非聚集索引。
复合索引:复合索引是索引键中包含多个列的索引。它可以是聚集的,也可以是非聚集的。
-- 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);
数据类型
在数据库的世界里,数据类型就像是用来存放特定类型信息的不同形状的容器。就像你不会把液体放在篮子里或把固体放在罐子里一样,数据库需要强制使用特定的数据类型来确保数据的完整性和一致性。
SQL 中的一些常见数据类型包括:
INT
或INTEGER
:存储整数,如42
或17
。FLOAT
或DOUBLE
:存储十进制数,如3.14159
或0.00005
。VARCHAR
或TEXT
:存储文本数据,如名称或描述。DATE
或DATETIME
:存储日期和时间值,如'2023-05-06'
或'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
);
在这个例子中,我们创建一个表,其中包含(整数)、(最多 50 个字符的字符串)、(整数)和(布尔值,默认值为或 true)users
的列。idnameageis_active1
连接简介
连接就像连接数据库中不同表的桥梁,允许您组合和检索来自多个来源的相关数据。它们是关系数据库中的基本概念,对于高效查询和操作数据至关重要。
内连接
内连接就像两个表之间的友好握手,其中只有两个表中具有匹配值的行才会包含在结果集中。这是一种基于公共列或一组列来组合多个表中数据的方法。
SELECT users.name, orders.order_date
FROM users
INNER JOIN orders ON users.id = orders.user_id;
在这个例子中,我们name
从users
表中检索列,order_date
从orders
表中检索列,但仅限于id
表中与表中users
匹配的行。user_idorders
三表内连接(示例)
假设我们有三张表:users
、orders
和products
。我们想要检索每个订单的用户姓名、订单日期和产品名称。我们可以通过对所有三个表执行内连接来实现此目的:
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;
在这里,我们首先在和列上连接users
和表。然后,我们将该连接的结果与和列上的表连接起来。这样,我们可以在单个查询中从所有三个表中检索数据,但仅限于满足连接条件的行。ordersiduser_idproductsproduct_idid
外连接简介
内连接就像友好的握手,而外连接更像是热情的拥抱。它们不仅包括两个表中匹配的行,还包括一个或两个表中不匹配的行,具体取决于外连接的类型。
右外连接
右外连接就像右表对左表的热情拥抱。它包括右表的所有行以及左表中的匹配行。如果左表中没有匹配的行,则结果将包含NULL
左表列的值。
SELECT users.name, orders.order_date
FROM users
RIGHT OUTER JOIN orders ON users.id = orders.user_id;
orders
在此示例中,我们从表(右表)中检索所有行,并name
从users
表(左表)中检索匹配的值。如果订单没有匹配的用户,则该name
列将包含NULL
。
JOIN 包含 NOT NULL 列
有时,您可能希望仅对非空列执行连接。当您想从结果集中排除缺少数据的行时,这会很有用。
SELECT users.name, orders.order_date
FROM users
INNER JOIN orders ON users.id = orders.user_id AND users.name IS NOT NULL;
users
在此示例中,我们在和表之间执行内连接orders
,但我们添加了附加条件,以确保结果集中users.name IS NOT NULL
仅包含非空值的行。name
跨 3 个表的外连接
与内连接示例类似,我们可以跨多个表执行外连接。假设我们想要检索所有订单以及用户姓名和产品名称,即使users
或products
表中有缺失值。
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;
这里,我们从表开始,对和表orders
执行左外连接。这确保所有订单都包含在结果集中,以及匹配的用户名和产品名称(如果有)。如果或表中没有匹配的行,则相应的列将包含值。usersproductsusersproductsNULL
别名
别名就像 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;
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;
在此示例中,我们对表执行自连接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()`]
}
在此示例中,我们定义了一个users
表,其列为id
、、和。标签指定为主键,表示自动递增,确保的唯一性,now()将的默认值设置为当前时间戳。usernameemailcreated_at[pk]id[increment][unique]email[default:]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()`]
}
在此示例中,我们添加了一个表,其中包含、、、和 的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
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
在这个更新的例子中,我们向表的列添加了一个[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
DBML 的优势
简单且易于理解的语法
与数据库无关的方法
dbdiagram.io上的免费可视化工具
可读性和可维护性的一致约定
丰富的文档和示例
结论
总而言之,关系数据库设计是现代应用程序中高效数据组织的支柱。了解其原理可让您创建强大且可扩展的数据库。接下来,我们将深入研究 SQL 语法,释放与数据库有效交互的能力。请继续关注我们对 SQL 世界的探索!