How to Create a Primary Key in SQL Server (T-SQL Examples)

This article demonstrates how to create a primary key in SQL Server when creating a table using Transact-SQL.

A primary key is one or more columns that have been configured as the unique identifier for a given table. Primary keys can be used to enforce data integrity in the table.

A table can only have one primary key, and primary keys can only be added to columns that are defined as NOT NULL.

This article demonstrates how to create a primary key in a new table (i.e. when creating the table). If you need to create a primary key in an existing table, see How to Add a Primary Key to an Existing Table in SQL Server.

Example 1 – Create a Table with a Primary Key

First I’ll create a test database:

CREATE DATABASE PK_Test;

Now create a new table that includes a primary key constraint:

USE PK_Test;

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

This created a new table called Colors which has a primary key constraint on its ColorId column.

Example 2 – Check the Primary Key Constraint

We can run the following code to return a list of primary key constraints in the database:

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

Result:

+------------------------------+--------+-------------------+-------------------+
| name                         | type   | unique_index_id   | is_system_named   |
|------------------------------+--------+-------------------+-------------------|
| PK__Colors__8DA7674DD34F4585 | PK     | 1                 | 1                 |
+------------------------------+--------+-------------------+-------------------+

I’ve narrowed the columns down for this example. The sys.key_constraints system view returns more columns than this. You can always use the * wildcard to return all columns if you wish.

We can see by the query result that this database has only one primary key (the one we just created).

In this case the primary key was automatically named by the system. You also have the option of providing your own name (more on that later).

Example 3 – Check the Index

By default a clustered index is created when you create the primary key. You can specify the clustered index explicitly or let it be created automatically. You also have the option of specifying a nonclustered index.

Here’s a query that returns the index that was created automatically when I created the above primary key:

SELECT *
FROM sys.indexes
WHERE name = 'PK__Colors__8DA7674DD34F4585';

Result (using vertical output):

object_id                  | 885578193
name                       | PK__Colors__8DA7674DD34F4585
index_id                   | 1
type                       | 1
type_desc                  | CLUSTERED
is_unique                  | 1
data_space_id              | 1
ignore_dup_key             | 0
is_primary_key             | 1
is_unique_constraint       | 0
fill_factor                | 0
is_padded                  | 0
is_disabled                | 0
is_hypothetical            | 0
is_ignored_in_optimization | 0
allow_row_locks            | 1
allow_page_locks           | 1
has_filter                 | 0
filter_definition          | NULL
compression_delay          | NULL
suppress_dup_key_messages  | 0
auto_created               | 0

In this case I narrowed the results to just the row that contains the same name of the primary key I just created. You can always remove the WHERE clause if you need more results to be returned.

We can see that this index has a type_desc of CLUSTERED.

Example 4 – Naming the Primary Key

The primary key that we created above was automatically named by the system. You can provide your own name if you prefer.

Here’s an example of specifying a name for the primary key. In this case I also specify a nonclustered index.

USE PK_Test;

CREATE TABLE Cats
(
    CatId int IDENTITY (1,1) NOT NULL, 
       CONSTRAINT PK_Cats_CatId PRIMARY KEY NONCLUSTERED (CatId),
    CatName varchar(50)
);

In this case I use the optional CONSTRAINT keyword to indicate the start of the definition of the primary key, followed by my chosen name for the primary key. I also use the NONCLUSTERED keyword to specify that an unclustered index.

Check the primary key:

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

Result:

+------------------------------+--------+-------------------+-------------------+
| name                         | type   | unique_index_id   | is_system_named   |
|------------------------------+--------+-------------------+-------------------|
| PK__Colors__8DA7674DD34F4585 | PK     | 1                 | 1                 |
| PK_Cats_CatId                | PK     | 2                 | 0                 |
+------------------------------+--------+-------------------+-------------------+

Check the index:

SELECT *
FROM sys.indexes
WHERE name = 'PK_Cats_CatId';

Result (using vertical output):

object_id                  | 917578307
name                       | PK_Cats_CatId
index_id                   | 2
type                       | 2
type_desc                  | NONCLUSTERED
is_unique                  | 1
data_space_id              | 1
ignore_dup_key             | 0
is_primary_key             | 1
is_unique_constraint       | 0
fill_factor                | 0
is_padded                  | 0
is_disabled                | 0
is_hypothetical            | 0
is_ignored_in_optimization | 0
allow_row_locks            | 1
allow_page_locks           | 1
has_filter                 | 0
filter_definition          | NULL
compression_delay          | NULL
suppress_dup_key_messages  | 0
auto_created               | 0

So we can see that this time the type_desc is NONCLUSTERED.

Note that when creating a table, CLUSTERED can be specified for only one constraint. If it’s specified for a UNIQUE constraint and a PRIMARY KEY constraint is also specified, the PRIMARY KEY defaults to NONCLUSTERED.

Example 5 – Create a Primary Key on a Nullable Column

A primary key can only be created for columns that are defined as NOT NULL. If you try to create a primary key on a column that is set to NULL, you’ll get an error.

However, if you don’t specify the nullability, the column is set to NOT NULL by default.

To demonstrate this, let’s create another table, but this time, we’ll set it to NULL:

USE PK_Test;

CREATE TABLE Dogs
(
    DogId int IDENTITY (1,1) NULL PRIMARY KEY,
    DogName varchar(50)
);

Result:

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

As expected, we get an error.

Let’s remove NULL from the table definition and try again:

USE PK_Test;

CREATE TABLE Dogs
(
    DogId int IDENTITY (1,1) PRIMARY KEY,
    DogName varchar(50)
);

Result:

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

This time the table was created successfully.

Let’s take a look at it:

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 = 'DogId';

Result:

+---------+----------+---------------+---------------+
| Table   | Column   | is_nullable   | is_identity   |
|---------+----------+---------------+---------------|
| Dogs    | DogId    | 0             | 1             |
+---------+----------+---------------+---------------+

So we can see that it’s not nullable, because the is_nullable flag is set to 0.

Example 6 – Primary Key on Multiple Columns

You can also create a primary key on multiple columns. Multicolumn primary keys are also known as composite primary keys. To create a composite primary key, simply separate the columns with a comma when defining the key.

Like this:

CONSTRAINT PK_Name PRIMARY KEY (Column1, Column2)

Here’s an example of a situation where a multicolumn primary key could be used:

CREATE TABLE Musician (
MusicianId int NOT NULL,
FirstName varchar(60),
LastName varchar(60),
CONSTRAINT PK_Musician PRIMARY KEY (MusicianID)
);

CREATE TABLE Band (
BandId int NOT NULL,
BandName varchar(255),
CONSTRAINT PK_Band PRIMARY KEY (BandId)
);

CREATE TABLE BandMember (
MusicianId int NOT NULL,
BandId int NOT NULL,
CONSTRAINT PK_BandMember PRIMARY KEY (MusicianID, BandId),
CONSTRAINT FK_BandMember_Band FOREIGN KEY (BandId) REFERENCES Band(BandId),
CONSTRAINT FK_BandMember_Musician FOREIGN KEY (MusicianId) REFERENCES Musician(MusicianId)
);

In this example, the BandMember table has a multicolumn primary key. In this case each column in the primary key is also a foreign key to the primary key of another table, but this is not a requirement.

See How to Create a Composite Primary Key in SQL Server for a more detailed explanation of this example.

Also see How to Create a Composite Foreign Key in SQL Server for an example that takes it a step further with a multicolumn foreign key that references the above composite primary key.