青少年编程与数学 02-002 Sql Server 数据库应用 09课题、规则、约束和默认值
本课题介绍了SQL Server中规则、约束和默认值的概念和应用。规则用于限制列数据的输入,但已在新版SQL Server中被弃用,推荐使用CHECK约束替代。约束确保数据的准确性和可靠性,包括NOT NULL、UNIQUE、PRIMARY KEY、FOREIGN KEY、CHECK和DEFAULT等类型。默认值为列指定默认值,以保证数据完整性并简化数据输入。
课题摘要:
本课题介绍了SQL Server中规则、约束和默认值的概念和应用。规则用于限制列数据的输入,但已在新版SQL Server中被弃用,推荐使用CHECK约束替代。约束确保数据的准确性和可靠性,包括NOT NULL、UNIQUE、PRIMARY KEY、FOREIGN KEY、CHECK和DEFAULT等类型。默认值为列指定默认值,以保证数据完整性并简化数据输入。此外,讨论了数据库关系、一致性、完整性和可维护性的重要性,这些概念对于维护数据库的准确性、可靠性和易管理性至关重要。通过合理使用规则、约束和默认值,可以提高数据库的查询效率和数据完整性。
一、规则
在 SQL Server 2022 中,规则(Rule)是一种数据库对象,用于限制列数据的输入。规则可以定义在数据库级别,并且可以绑定到一个或多个列上,以确保输入的数据满足特定的条件。规则通常用于数据验证、数据转换和数据限制等场景。
规则的创建使用 CREATE RULE
语句,其基本语法如下:
sql
CREATE RULE [schema_name.]rule_name
AS condition_expression
其中 schema_name
是规则所属架构的名称,rule_name
是新规则的名称,condition_expression
是定义规则的条件表达式。规则表达式可以包含算术运算符、关系运算符和谓词(如 IN、LIKE、BETWEEN)等元素,但不能引用列或其他数据库对象,也不能使用用户定义的函数。
创建规则后,可以使用 sp_bindrule
存储过程将规则绑定到列或别名数据类型,例如:
sql
EXEC sp_bindrule 'rule_name', 'table_name.column_name'
如果需要解除规则的绑定,可以使用 sp_unbindrule
存储过程,例如:
sql
EXEC sp_unbindrule 'table_name.column_name'
最后,如果规则不再需要,可以使用 DROP RULE
语句将其删除,例如:
sql
DROP RULE rule_name
需要注意的是,规则不能绑定到 text
、ntext
、image
、varchar(max)
、nvarchar(max)
、varbinary(max)
、xml
、CLR 用户定义类型或 timestamp
列,也不能绑定到计算列。此外,如果列同时有与之相关联的默认值和规则,则默认值必须在规则定义的范围内。
在 SQL Server 中,规则(Rule)通常与 CREATE RULE
和 sp_bindrule
存储过程一起使用。以下是一个完整的示例,展示了如何创建和使用规则来限制数据输入。
二、规则应用示例
假设我们有一个 Employees
表,我们想要确保插入或更新到 Salary
列的薪水数据在 10000 到 50000 之间。我们可以按照以下步骤创建和使用规则:
-
创建规则 :
首先,我们需要创建一个规则,名为
SalaryRangeRule
,用于限制薪水的范围。sqlCREATE RULE SalaryRangeRule AS @value >= 10000 AND @value <= 50000;
-
将规则绑定到列 :
然后,我们需要将这个规则绑定到
Employees
表的Salary
列上。我们使用sp_bindrule
存储过程来实现这一点。sqlEXEC sp_bindrule 'SalaryRangeRule', 'Employees.Salary';
-
创建 Employees 表 :
接下来,我们需要确保
Employees
表存在,并且有一个Salary
列。sqlCREATE TABLE Employees ( EmployeeID INT PRIMARY KEY, FirstName NVARCHAR(100) NOT NULL, LastName NVARCHAR(100) NOT NULL, Salary DECIMAL(10, 2) );
-
尝试插入数据 :
现在,如果我们尝试插入一个薪水值到
Employees
表,这个值必须符合我们之前创建的规则。sqlINSERT INTO Employees (EmployeeID, FirstName, LastName, Salary) VALUES (1, 'John', 'Doe', 12000); -- 这将成功,因为薪水在范围内 INSERT INTO Employees (EmployeeID, FirstName, LastName, Salary) VALUES (2, 'Jane', 'Doe', 60000); -- 这将失败,因为薪水超出了范围
-
查看错误信息 :
当尝试插入不符合规则的数据时,SQL Server 将返回一个错误。错误信息将指出违反了哪个规则。
-
解除规则绑定 (如果需要):
如果我们需要对
Salary
列的约束进行更改,或者不再需要这个规则,我们可以使用sp_unbindrule
存储过程来解除规则的绑定。sqlEXEC sp_unbindrule 'Employees.Salary';
-
删除规则 (如果需要):
如果规则不再需要,我们可以使用
DROP RULE
语句来删除它。sqlDROP RULE SalaryRangeRule;
请注意,规则在 SQL Server 2005 之后的版本中已经被弃用,并且在 SQL Server 2016 及更高版本中不再支持。在新版本的 SQL Server 中,推荐使用 CHECK 约束来替代规则的功能。因此,这个示例仅适用于 SQL Server 2005 到 SQL Server 2014 的版本。在更新的版本中,你应该使用 CHECK 约束来实现类似的功能。
三、约束
在数据库管理系统中,约束(Constraints)是一种用于确保数据库中数据准确性和可靠性的规则。约束定义了可以存储在表中的数据类型、所需的数据格式以及必须满足的条件。它们帮助维护数据库的完整性,确保数据的一致性和准确性。
以下是一些常见的约束类型:
-
NOT NULL 约束 :
确保列不能包含 NULL 值。例如,如果一个表有一个名为
FirstName
的列,并且你希望确保每个记录都有这个名字,你可以对这个列施加 NOT NULL 约束。 -
UNIQUE 约束 :
确保列中的所有值都是唯一的,没有重复。这可以用于像身份证号码或电子邮件地址这样的字段,这些字段应该是唯一的。
-
PRIMARY KEY 约束 :
是一种特殊的 UNIQUE 约束,它唯一标识表中的每一行。一个表可以有一个主键,主键列的组合必须是唯一的,并且不能包含 NULL 值。
-
FOREIGN KEY 约束 :
用于在两个表之间建立链接(或关系),确保引用表中的值必须在主表中存在。这有助于维护表之间的引用完整性。
-
CHECK 约束 :
用于确保列中的值满足特定的条件。例如,你可以使用 CHECK 约束来确保年龄列只包含大于0的值。
-
DEFAULT 约束 :
为列定义一个默认值,如果插入行时没有为该列指定值,则使用默认值。
-
INDEX 约束 :
用于创建索引,可以提高查询性能。虽然不是直接的数据完整性约束,但它们与数据的存储和检索方式有关。
-
CASCADING 约束 :
与 FOREIGN KEY 约束一起使用,定义了当主键表中的数据被更新或删除时,应该如何处理引用数据。例如,可以设置级联更新或级联删除。
约束可以在创建表时定义,也可以在表创建后添加。例如,创建一个带有多个约束的表的 SQL 语句可能如下所示:
sql
CREATE TABLE Employees (
EmployeeID INT PRIMARY KEY,
FirstName NVARCHAR(100) NOT NULL,
LastName NVARCHAR(100) NOT NULL,
Email NVARCHAR(255) UNIQUE,
PhoneNumber NVARCHAR(15),
Salary DECIMAL(10, 2) CHECK (Salary >= 0),
JoinDate DATE NOT NULL
);
在这个例子中,Employees
表有多个约束,包括主键、非空字段、唯一字段和检查约束,以确保数据的完整性和准确性。
四、约束应用示例
当然,以下是一个使用多种约束的综合示例。我们将创建一个 Students
表,用于管理学生信息,包括学生ID、姓名、年龄、性别、电子邮件和入学日期。我们将对这个表施加多种约束,以确保数据的完整性和准确性。
sql
-- 创建 Students 表
CREATE TABLE Students
(
-- 学生ID作为主键,必须唯一且非空
StudentID INT PRIMARY KEY,
-- 姓名字段,必须非空,且限制长度不超过100字符
Name NVARCHAR(100) NOT NULL,
-- 年龄字段,必须在5到100岁之间
-- CHECK约束用于限制年龄范围
Age INT CHECK (Age BETWEEN 5 AND 100),
-- 性别字段,限制性别只能为'Male'或'Female'
-- CHECK约束用于限制性别取值
Gender NVARCHAR(6) CHECK (Gender IN ('Male', 'Female')),
-- 电子邮件字段,必须唯一且符合电子邮件格式
-- UNIQUE约束用于确保电子邮件不重复
-- 可以使用正则表达式来限制电子邮件格式(SQL Server 2016及以上版本支持正则表达式)
Email NVARCHAR(255) UNIQUE CHECK (Email LIKE '%_@__%.__%'),
-- 入学日期字段,必须非空,且必须是未来的日期
-- NOT NULL约束用于确保字段不为空
-- CHECK约束用于确保日期是未来的日期
EnrollmentDate DATE NOT NULL CHECK (EnrollmentDate > GETDATE())
);
-- 插入符合约束的数据
INSERT INTO Students (StudentID, Name, Age, Gender, Email, EnrollmentDate)
VALUES
(1, 'John Doe', 20, 'Male', 'john.doe@example.com', '2023-09-01'),
(2, 'Jane Doe', 22, 'Female', 'jane.doe@example.com', '2023-10-01');
-- 尝试插入不符合约束的数据
-- 以下插入将失败,因为年龄超出了5到100的范围
INSERT INTO Students (StudentID, Name, Age, Gender, Email, EnrollmentDate)
VALUES
(3, 'Alice Johnson', 15, 'Male', 'alice.johnson@example.com', '2023-11-01');
-- 以下插入将失败,因为电子邮件字段不是唯一的
INSERT INTO Students (StudentID, Name, Age, Gender, Email, EnrollmentDate)
VALUES
(4, 'Bob Smith', 23, 'Male', 'john.doe@example.com', '2023-12-01');
-- 以下插入将失败,因为入学日期不是未来的日期
INSERT INTO Students (StudentID, Name, Age, Gender, Email, EnrollmentDate)
VALUES
(5, 'Carol White', 19, 'Female', 'carol.white@example.com', '2022-01-01');
在这个示例中,我们使用了以下约束:
PRIMARY KEY
:确保StudentID
列的值是唯一的,并且非空。NOT NULL
:确保Name
和EnrollmentDate
列的值不能为 NULL。CHECK
:用于Age
、Gender
和Email
列,确保它们满足特定的条件。UNIQUE
:确保Email
列的值是唯一的。LIKE
:在Email
的CHECK
约束中使用,确保电子邮件符合基本的格式。
请注意,CHECK
约束中的正则表达式使用是 SQL Server 2016 及以上版本支持的功能。在较早版本的 SQL Server 中,你可能需要使用其他方法来验证电子邮件格式,例如使用触发器或在应用程序层面进行验证。
五、默认值
在数据库管理系统中,默认值(Default Value)是一种约束,它为列指定了一个默认的值,这个值会在插入新记录时使用,如果插入操作没有为该列明确提供一个值的话。默认值可以帮助确保数据的完整性,减少数据输入的错误,并提供列的一致性。
默认值可以在创建表时定义,也可以在表创建后添加。以下是一些关于默认值的关键点:
-
自动填充 :
当插入新记录而没有为具有默认值的列提供值时,数据库管理系统会自动使用该默认值。
-
数据完整性 :
默认值可以用于确保某些重要的列(如创建日期、创建用户等)总是有值,从而维护数据的完整性。
-
简化数据输入 :
对于经常有相同值的列,使用默认值可以简化数据输入过程,减少重复输入。
-
覆盖默认值 :
在插入或更新记录时,如果提供了一个值,即使它是一个 NULL 值,也会覆盖默认值。
-
系统版本 :
在某些数据库系统中,如 SQL Server,有两种类型的默认值:固定默认值和触发器默认值。固定默认值是直接在表定义中设置的,而触发器默认值是通过触发器动态生成的。
以下是在 SQL Server 中为表的列设置默认值的示例:
sql
-- 创建一个新表,并为某些列指定默认值
CREATE TABLE Employees
(
EmployeeID INT PRIMARY KEY,
FirstName NVARCHAR(100) NOT NULL,
LastName NVARCHAR(100) NOT NULL,
HireDate DATE NOT NULL DEFAULT GETDATE(), -- 默认值为当前日期
Email NVARCHAR(255)
);
-- 插入一个新员工记录,没有为 Email 列提供值
INSERT INTO Employees (EmployeeID, FirstName, LastName, HireDate)
VALUES (1, 'John', 'Doe', '2023-10-05');
-- 插入另一个员工记录,Email 列将使用默认的 NULL 值
INSERT INTO Employees (EmployeeID, FirstName, LastName)
VALUES (2, 'Jane', 'Doe');
在这个例子中,HireDate
列有一个默认值,即当前日期(GETDATE()
),如果在插入记录时没有为 HireDate
提供值,将自动使用当前日期。而 Email
列没有指定默认值,如果在插入记录时没有为 Email
提供值,它将默认为 SQL Server 中的 NULL 值。
请注意,对于使用默认值的列,如果希望在插入记录时明确使用默认值,可以在插入语句中省略该列,或者为该列提供 NULL 值(如果默认值是 NULL)。
六、关系(Relationship)
在数据库管理系统中,关系(Relationship)是指不同数据表之间的逻辑联系。关系数据库管理系统(RDBMS)中的关系通常指的是表之间的关系,这些关系定义了表如何相互连接和交互。关系的目的在于保持数据的一致性、完整性和可维护性。
关系可以是以下几种类型:
-
一对一(One-to-One) :
每个表中的记录只与另一个表中的一条记录相关。例如,一个员工表可能与一个员工详细信息表有一对一的关系,其中每个员工只有一个详细的记录。
-
一对多(One-to-Many) :
一个表中的记录可以与另一个表中的多条记录相关。例如,一个部门表可能与员工表有一对多的关系,其中每个部门可以有多个员工。
-
多对一(Many-to-One) :
这是一对多关系的逆关系,多个记录在一个表中与另一个表中的一条记录相关。例如,如上所述的员工表与部门表的关系。
-
多对多(Many-to-Many) :
两个表中的记录可以有多条对应关系。例如,学生和课程之间可能存在多对多的关系,因为一个学生可以选修多个课程,同时一个课程也可以被多个学生选修。多对多关系通常通过创建第三个关联表(也称为连接表或交叉引用表)来实现,这个表包含外键指向两个相关表的主键。
关系通常通过外键约束来实现,外键是在一个表中用来指向另一个表的主键的字段。这种约束确保了引用的数据的完整性。例如,如果员工表中有一个指向部门表的外键,那么每个员工记录都必须引用部门表中存在的一个部门。
以下是一个简单的示例,展示了两个表之间的一对多关系:
sql
-- 创建部门表
CREATE TABLE Departments
(
DepartmentID INT PRIMARY KEY,
DepartmentName NVARCHAR(100) NOT NULL
);
-- 创建员工表
CREATE TABLE Employees
(
EmployeeID INT PRIMARY KEY,
EmployeeName NVARCHAR(100) NOT NULL,
DepartmentID INT,
FOREIGN KEY (DepartmentID) REFERENCES Departments(DepartmentID)
);
在这个例子中,Departments
表和 Employees
表之间存在一对多的关系。每个部门可以有多个员工,但每个员工只能属于一个部门。Employees
表中的 DepartmentID
是一个外键,它引用了 Departments
表的 DepartmentID
主键。
通过这种方式,关系数据库管理系统能够组织和存储结构化数据,同时确保数据之间的关系清晰和一致。
七、一致性、完整性和可维护性
在数据库管理系统中,一致性、完整性和可维护性是三个核心概念,它们确保数据的准确性、可靠性和易于管理。下面分别解释这些概念:
-
一致性(Consistency) :
一致性指的是数据在特定时间内的相同视图或状态。在数据库中,一致性通常与事务处理相关,确保事务的执行不会违反数据库的预定规则,即使在并发操作或系统故障的情况下也能保持数据的预期状态。例如,当一个事务从一个账户转账到另一个账户时,系统必须确保两个账户的余额在任何时候都是准确的,不会出现负数余额,这就是一致性的一种体现。
-
完整性(Integrity) :
完整性是指数据的准确性和完整性,确保数据符合预定的规则和约束。数据库完整性可以通过以下类型来实现:
- 实体完整性:确保表中的每一行都有一个唯一的标识符,通常通过主键来实现。
- 域完整性:确保列中的值符合特定的数据类型和格式。
- 参照完整性:确保外键约束得到满足,即外键列中的值必须在相关联的表中存在。
- 用户定义的完整性:根据特定业务规则定义的约束,例如,某些字段的值必须在特定的范围内。
-
可维护性(Maintainability) :
可维护性是指数据库的易管理性,包括数据的更新、优化和故障排除的容易程度。一个具有高可维护性的数据库设计应该是清晰的,结构良好,且易于理解和修改。这通常涉及到:
- 清晰的表结构和关系:表应该有明确的目的,字段应该有描述性的名称,关系应该易于理解。
- 适当的索引:为了提高查询性能,应该为经常查询的列创建索引,但也要避免过度索引,以免影响插入和更新的性能。
- 规范化:通过规范化来消除数据冗余,减少数据异常,提高数据的一致性。
- 文档和注释:数据库设计和代码应该有充分的文档和注释,以便其他开发者或管理员能够理解和维护。
这三个概念是相互关联的。一致性确保数据在事务处理过程中保持预期的状态,完整性确保数据符合业务规则和约束,而可维护性确保数据库设计和实现的长期可管理性和可扩展性。数据库管理员和开发者需要共同努力,以确保数据库系统在整个生命周期中都能满足这些要求。