如何将主键添加到 SQL Server 中的现有表(T-SQL 示例)

发布于

本文演示如何使用 Transact-SQL 向 SQL Server 中的现有表添加主键。

主键是已配置为给定表的唯一标识符的列。

通常在创建表时创建主键约束,但也可以将主键添加到现有表。

请注意,一个表只能有一个主键。因此,如果表已有主键,则无法添加主键。

此外,主键只能添加到定义为 的列中。NOT NULL

示例 1 – 添加主键约束

在此示例中,我创建了一个表,但忘记添加主键约束。因此,我随后返回并更改表以具有主键。

创建表(但忘记创建主键):

USE Test;

CREATE TABLE Colors ( ColorId int IDENTITY (1,1) NOT NULL, ColorName varchar(50) );

输出:

Commands completed successfully.
Total execution time: 00:00:00.058

糟糕 - 我忘了创建主键!

没关系!我们现在可以添加一个:

ALTER TABLE Colors ADD CONSTRAINT PK_Colors_ColorId PRIMARY KEY CLUSTERED (ColorId);

输出:

Commands completed successfully.
Total execution time: 00:00:00.031

现在,这为列添加了约束。PRIMARY KEY``ColorId

示例 2 – 检查主键约束

让我们运行以下代码以返回数据库中的主键约束列表:

SELECT name, type, unique_index_id, is_system_named FROM sys.key_constraints WHERE type = ‘PK’;

输出:

+------------------------------+--------+-------------------+-------------------+
| name                         | type   | unique_index_id   | is_system_named   |
|------------------------------+--------+-------------------+-------------------|
| PK__MyTest__606C418F16F9CCCF | PK     | 1                 | 1                 |
| PK__Client__96ADCE1ACB91C2A9 | PK     | 1                 | 1                 |
| PK_Colors_ColorId            | PK     | 1                 | 0                 |
+------------------------------+--------+-------------------+-------------------+

结果会有所不同,具体取决于数据库中的主键。

另请注意,此系统视图返回的列数比我在此处指定的列多,但如果需要,可以使用通配符返回所有列。*

示例 3 – 向允许 NULL 值的列添加主键

主键只能添加到定义为 的列中。如果尝试将主键添加到可为 null 的列,则会收到错误。NOT NULL

为了演示这一点,让我们创建另一个表,但这一次,我们还忘记将列指定为 :NOT NULL

USE Test;

CREATE TABLE Colors2 ( ColorId int, ColorName varchar(50) );

我们可以运行以下查询来检查该列是否允许空值:

SELECT t.name AS ‘Table’, c.name AS ‘Column’, c.is_nullable, c.is_identity FROM sys.columns c INNER JOIN sys.tables T ON c.object_id = t.object_id WHERE c.name = ‘ColorId’;

输出:

+---------+----------+---------------+---------------+
| Table   | Column   | is_nullable   | is_identity   |
|---------+----------+---------------+---------------|
| Colors  | ColorId  | 0             | 1             |
| Colors2 | ColorId  | 1             | 0             |
+---------+----------+---------------+---------------+

我们可以看到,我们之前(在表中)创建的那个是可为空的,并且是一个标识列。第二个(在表中)可为空,并且不是标识列。Colors``Colors2

现在,让我们尝试向可为空的列添加主键约束:

ALTER TABLE Colors2 ADD CONSTRAINT PK_Colors2_ColorId PRIMARY KEY CLUSTERED (ColorId);

输出:

Msg 8111, Level 16, State 1, Line 1
Cannot define PRIMARY KEY constraint on nullable column in table 'Colors2'.
Msg 1750, Level 16, State 0, Line 1
Could not create constraint or index. See previous errors.

因此,在这种情况下,我们需要在尝试将其定义为主键之前将列更改为 a。NOT NULL

我们可以在语句中使用将此列设置为 :ALTER COLUMN``ALTER TABLE``NOT NULL

ALTER TABLE Colors2 ALTER COLUMN ColorId int NOT NULL;

让我们再次检查该列:

SELECT t.name AS ‘Table’, c.name AS ‘Column’, c.is_nullable, c.is_identity FROM sys.columns c INNER JOIN sys.tables T ON c.object_id = t.object_id WHERE c.name = ‘ColorId’;

输出:

+---------+----------+---------------+---------------+
| Table   | Column   | is_nullable   | is_identity   |
|---------+----------+---------------+---------------|
| Colors  | ColorId  | 0             | 1             |
| Colors2 | ColorId  | 0             | 0             |
+---------+----------+---------------+---------------+

所以我们可以看到现在设置为 ,这意味着它不可为空(它不能包含 NULL 值)。Colors2``0

另请注意,该列_不是_标识列。我稍后会讨论这个问题。

无论如何,现在该列已定义为我们可以继续添加主键:NOT NULL

ALTER TABLE Colors2 ADD CONSTRAINT PK_Colors2_ColorId PRIMARY KEY CLUSTERED (ColorId);

输出:

Commands completed successfully.
Total execution time: 00:00:00.048

为了验证,让我们再次检查此表的所有主键约束:

SELECT name, type, unique_index_id, is_system_named FROM sys.key_constraints WHERE type = ‘PK’;

输出:

+------------------------------+--------+-------------------+-------------------+
| name                         | type   | unique_index_id   | is_system_named   |
|------------------------------+--------+-------------------+-------------------|
| PK__MyTest__606C418F16F9CCCF | PK     | 1                 | 1                 |
| PK__Client__96ADCE1ACB91C2A9 | PK     | 1                 | 1                 |
| PK_Colors_ColorId            | PK     | 1                 | 0                 |
| PK_Colors2_ColorId           | PK     | 1                 | 0                 |
+------------------------------+--------+-------------------+-------------------+

我们调用的新主键已添加到列表中。PK_Colors2_ColorId

示例 4 – 将列更改为标识列

主键通常应用于标识列。标识列是这样定义的,带有关键字,后跟可选的种子和括号内的增量值。IDENTITY

将新行添加到表中时,SQL Server 将为标识列提供唯一的增量值。

如果您打算使用标识列,则需要已经这样做了。不能将现有列更改为标识列。

当我之前运行查询时,我们可以看到该列_不是_标识列(我们知道这一点,因为设置为 )。这意味着我在非标识列上创建了主键。Colors2.ColorId``is_identity``0``PK_Colors2_ColorId

如果我们尝试将表更改为标识列,会发生什么情况:

ALTER TABLE Colors2 ALTER COLUMN ColorId int IDENTITY (1,1) NOT NULL PRIMARY KEY;

输出:

Msg 156, Level 15, State 1, Line 3
Incorrect syntax near the keyword 'IDENTITY'.

如前所述,为了克服这个问题,我们需要删除该列并重新开始。

如果列已包含数据,则需要执行一些额外的工作。这超出了本文的范围,但下面是删除上述列并将其重新创建为标识列的示例:

USE Test;

DROP TABLE Colors2;

CREATE TABLE Colors2 ( ColorId int IDENTITY (1,1) NOT NULL PRIMARY KEY, ColorName varchar(50) );

输出:

Commands completed successfully.
Total execution time: 00:00:00.049

请注意,这次我没有提供主键约束的名称。在这种情况下,系统将为其创建一个名称。

快速检查列:

SELECT t.name AS ‘Table’, c.name AS ‘Column’, c.is_nullable, c.is_identity FROM sys.columns c INNER JOIN sys.tables T ON c.object_id = t.object_id WHERE c.name = ‘ColorId’;

输出:

+---------+----------+---------------+---------------+
| Table   | Column   | is_nullable   | is_identity   |
|---------+----------+---------------+---------------|
| Colors  | ColorId  | 0             | 1             |
| Colors2 | ColorId  | 0             | 1             |
+---------+----------+---------------+---------------+

是的,它现在是一个标识列。

让我们再看一下此表的主键:

SELECT name, type, unique_index_id, is_system_named FROM sys.key_constraints WHERE type = ‘PK’;

输出:

+-------------------------------+--------+-------------------+-------------------+
| name                          | type   | unique_index_id   | is_system_named   |
|-------------------------------+--------+-------------------+-------------------|
| PK__MyTest__606C418F16F9CCCF  | PK     | 1                 | 1                 |
| PK__Client__96ADCE1ACB91C2A9  | PK     | 1                 | 1                 |
| PK_Colors_ColorId             | PK     | 1                 | 0                 |
| PK__Colors2__8DA7674D8F57294D | PK     | 1                 | 1                 |
+-------------------------------+--------+-------------------+-------------------+

所以我们现在有一个名为 .PK__Colors2__8DA7674D8F57294D