除了数据类型的限制,SQL Server还为我们提供了其他一些约束(constraint),包括:
所有上面这些约束,都可以在
CREATE TABLE Student( Id INT PRIMARY KEY, -- Id是主键,不能为NULL不能重复 SName VARCHAR(10) UNIQUE, -- SName可以为空不能重复 Enroll DATETIME NOT NULL, -- Enroll不能为空 Age INT CHECK(Age>18), -- Age必须大于18 IsFemale BIT DEFAULT(1), -- 默认为1 Score FLOAT -- 没有约束 )
演示:当表上已有约束,我们进行操作(增删改)时不能违反
INSERT Student(Id, SName, Enroll, Age, IsFemale, Score) VALUES(1, 'atai', '2022-11-14', 19, 0, 85);注意:特殊的NULL值
-- NULL值和非NULL值不违反UNIQUE约束 INSERT Student(Id, Enroll, Age, IsFemale, Score) VALUES(3, '2022-11-14', 19, 0, 85); -- NULL和NULL被认为是重复的 INSERT Student(Id, Enroll, Age, IsFemale, Score) VALUES(4, '2022-11-14', 19, 0, 85);
查看工具生成的其他写法(先列后约束):
T-SQL | mysql |
CREATE TABLE [dbo].[Student] ( [Id] INT NOT NULL, [SName] VARCHAR (10) NULL, [Enroll] DATETIME NOT NULL, [Age] INT NULL, [IsFemale] BIT DEFAULT ((1)) NULL, [Score] FLOAT (53) NULL, PRIMARY KEY CLUSTERED ([Id] ASC), UNIQUE NONCLUSTERED ([SName] ASC), CHECK ([Age]>(18)) ); |
CREATE TABLE `student` ( `Id` int NOT NULL, `SName` varchar(10) DEFAULT NULL, `Enroll` datetime NOT NULL, `Age` INT DEFAULT NULL, `IsFemale` bit(1) DEFAULT (1), `Score` float DEFAULT NULL, PRIMARY KEY (`Id`), UNIQUE KEY `SName` (`SName`), CONSTRAINT `student_chk_1` CHECK ((`Age` > 0)) ) ENGINE=InnoDB... |
右键:view code | 右键:Table-Inspector-DLL |
PRIMARY KEY和UNIQUE约束,都可以建在多列上,这时候就只能先列后约束的写法:
PRIMARY KEY ([Name], Age) UNIQUE ([Name], Age)
意思是某行中的Name和Age不能和其他某一行的Name和Age都相同(只有一个相同是可以的)
如果是在表上添加新列,可以像建表时一样,指定该列的一些约束,比如:
ALTER TABLE Student ADD Hobby VARCHAR(100) DEFAULT('coding');
表上已有列的约束,按是否独立,可分为两种方式:
除了非空约束,T-SQL和mysql使用相同方式。
|
T-SQL | mysql |
同:修改列(复习) | 非空 |
非空和默认 |
ADD/DROP CONSTRAINT |
其他 |
其他 |
注意:
当表中已有数据,我们也不能建立和数据不符的约束。
比如,不能:
注意这里面有一个常见的错误:添加一个没有DEFAULT且要求NOT NULL的新列!@想一想@:为什么?
因为添加新列后新列值必然为NULL,会和要求的NOT NULL约束冲突。
ALTER TABLE Student ADD Hobby VARCHAR(500) NOT NULL -- 报错 -- DEFAULT('coding') -- OK ;
PS:外键约束还会导致列无法被删除等……
NOT NULL以外的约束都是独立的,只能先DROP,再ADD。
CREATE TABLE Student( Id INT , SName VARCHAR(10) , Enroll DATETIME, Age INT , IsFemale BIT, Score FLOAT );
不指定约束的名称,系统会自动生成约束名,通常格式为:[约束种类]_[表名]_[随机字符串],如UQ_Student_737584F6d87643。
所以T-SQL中是可以指定约束名称的:
CREATE TABLE Student( Id INT CONSTRAINT PK_Student_Id PRIMARY KEY, SName VARCHAR(10) CONSTRAINT UQ_Student_SName UNIQUE, Enroll DATETIME NOT NULL, Age INT CONSTRAINT CK_Student_Age CHECK(Age>18), IsFemale BIT CONSTRAINT FK_Student_IsFemale DEFAULT(1), Score FLOAT );
注意:约束中加上表名,是因为约束是否重名是以数据库为单位进行检查的。(演示:重名约束)
这样在Explorer中可以查看生成的约束:
在ALTER TABLE之后使用ADD CONSTRAINT :
-- 在Id列上建立主键约束 ALTER TABLE Student ADD CONSTRAINT PK_Student_Id PRIMARY KEY(Id);
-- 在Enroll列上添加唯一约束 ALTER TABLE Student ADD CONSTRAINT UQ_Student_ENROLL UNIQUE(ENROLL);
-- CK_Age是添加约束的名称 ALTER TABLE Student ADD CONSTRAINT CK_Student_Age CHECK(Age>0);
-- 18是默认值,作用于Age列 ALTER TABLE Student ADD CONSTRAINT DF_Student_Age DEFAULT 18 FOR Age; -- 注意写法的差异
上述代码使用CONSTRAINT关键字指定了自定义的约束名称,便于我们删除。
在ALTER TABLE之后使用DROP CONSTRAINT :
ALTER TABLE Student DROP CONSTRAINT PK_Student_Id;
使用ALTER TABLE修改DEFAULT:
ALTER TABLE student modify IsFemale bit default(1);
自定义约束CEECK:
ALTER TABLE student -- MODIFY Age INT CHECK(Age>18); 不报错,但也不生效 ADD CONSTRAINT CK_Age CHECK(Age>18); -- DROP CONSTRAINT CK_Age;
唯一约束:
ALTER TABLE student -- ADD CONSTRAINT UQ_Student_SName UNIQUE(SName); DROP CONSTRAINT UQ_Student_SName;主键约束:
ALTER TABLE student -- ADD CONSTRAINT PK_Student_Id PRIMARY KEY(Id); DROP PRIMARY KEY; -- 不需要名字
我们通常也将“主键”和“主键约束”混用。
但严格来说,“主键”和“主键约束”并不是同一个概念:
我们说:
同学们要根据上下文综合理解(外键也一样)。
一张表只能有一个主键(列/约束),但可以有多个唯一(列/约束)。
唯一列可以做主键,但不一定是主键,有时候我们又将其称之为“候选”(码)。
唯一(列/约束)不强调其作用(标识),只强调其特征(不重复)。
@想一想@:应该选择哪一列做主键?
主键通常使用
自动编号(惯用名Id)。
相较于表中已有的、可以区分行数据的列(比如姓名/学号/身份证号,又被称之为“业务”主键)。这种“逻辑”主键可以:
PS:通俗版理解:
T-SQL为我们提供了两种自动编号:
整数类型,需要在建表时声明该列为自增。
T-SQL | mysql |
CREATE TABLE Student( -- 关键字IDENTITY Id INT IDENTITY, SName VARCHAR(50) |
CREATE TABLE Student( -- 关键字auto_increment Id INT auto_increment primary key, SName VARCHAR(50) |
没有这个限制 | 必须同时为主键 |
在INSERT插入数据的时候,自增列不能再由开发人员赋值。
-- 错误:试图把Id设成20 INSERT INTO Student(Id, SName) VALUES (20, 'atai') -- 正确:Id由数据库自动生成 INSERT INTO Student(SName) VALUES ('atai') |
没有这个限制 |
注意:一个表中只能有一个自增列。
每插入一条新数据,就在上一条数据编号的基础上自增(默认从1开始,每次+1)作为新数据的编号。
演示:插入数据后自动生成自增列值
注意:自增列的值可以不连续,因为:
Global/Universal Unique Id。全球/宇宙唯一Id,^_^
字符串类型。建表时无须其他指定:
CREATE TABLE GUIDSample(Id VARCHAR(50) )在插入数据时调用函数
T-SQL | mysql |
NEWID() | uuid() |
该值根据当前时间和网卡的MAC地址等,由数据库自动生成。
#常见面试题#
和GUID想比较,自增列的:
通常当我们使用数据库集群(可简单理解为同一张表分别放在多个数据库中)的时候,比如3台数据库A,B,C:
如果还是以单个数据库为域自增,就必然出现冲突:
用SELECT * FROM T WHERE Id = 3 会取出3行数据出来,完全不对劲!
如果要检查所有数据库找到当前最大值(或者检查某个地方的@IDENTITY)之后再自增,效率就会降低。
有一种解决方案就是这样设置他们表上的ID列:
他们的ID是不是就可以依赖自己(当前数据库)保证ID永远不会重复了?
这实际上就是设置数据库的
比如:从10开始,每次增加3
T-SQL |
mysql |
IDENTITY(10,3) |
CREATE TABLE student ( Id int NOT NULL AUTO_INCREMENT PRIMARY KEY, SName varchar(50) ) AUTO_INCREMENT=10; SET @@auto_increment_offset=3; |
建表时指定 作用于该表 |
起始值针对表 步长为全局变量,作用于当前连接 |
多快好省!前端后端,线上线下,名师精讲
更多了解 加: