如何将主键添加到 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