How do you list the primary key of a SQL Server table?

Viewed 223722

Simple question, how do you list the primary key of a table with T-SQL? I know how to get indexes on a table, but can't remember how to get the PK.

27 Answers
SELECT Col.Column_Name from 
    INFORMATION_SCHEMA.TABLE_CONSTRAINTS Tab, 
    INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE Col 
WHERE 
    Col.Constraint_Name = Tab.Constraint_Name
    AND Col.Table_Name = Tab.Table_Name
    AND Constraint_Type = 'PRIMARY KEY'
    AND Col.Table_Name = '<your table name>'

Is using MS SQL Server you can do the following:

--List all tables primary keys
select * from information_schema.table_constraints
where constraint_type = 'Primary Key'

You can also filter on the table_name column if you want a specific table.

I like the INFORMATION_SCHEMA technique, but another I've used is: exec sp_pkeys 'table'

I am telling a simple Technic which I follow

SP_HELP 'table_name'

run this code as query. Mention your table name at place of table_name for which you want to know Primary Key (don't forget the single quotes). The result will show like attached Image. Hope it will help you

enter image description here

The system stored procedure sp_help will give you the information. Execute the following statement:

execute sp_help table_name
SELECT t.name AS 'table', i.name AS 'index', it.xtype,

(SELECT c.name FROM syscolumns c INNER JOIN sysindexkeys k 
    ON k.indid = i.indid 
        AND c.colid = k.colid 
        AND c.id = t.id 
        AND k.keyno = 1 
        AND k.id = t.id)
    AS 'column1',

(SELECT c.name FROM syscolumns c INNER JOIN sysindexkeys k 
    ON k.indid = i.indid 
        AND c.colid = k.colid 
        AND c.id = t.id 
        AND k.keyno = 2 
        AND k.id = t.id)
    AS 'column2',

(SELECT c.name FROM syscolumns c INNER JOIN sysindexkeys k 
    ON k.indid = i.indid 
        AND c.colid = k.colid 
        AND c.id = t.id 
        AND k.keyno = 3
        AND k.id = t.id)
    AS 'column3',

(SELECT c.name FROM syscolumns c INNER JOIN sysindexkeys k 
    ON k.indid = i.indid 
        AND c.colid = k.colid 
        AND c.id = t.id 
        AND k.keyno = 4
        AND k.id = t.id)
    AS 'column4',

(SELECT c.name FROM syscolumns c INNER JOIN sysindexkeys k 
    ON k.indid = i.indid 
        AND c.colid = k.colid 
        AND c.id = t.id 
        AND k.keyno = 5
        AND k.id = t.id)
    AS 'column5',

(SELECT c.name FROM syscolumns c INNER JOIN sysindexkeys k 
    ON k.indid = i.indid 
        AND c.colid = k.colid 
        AND c.id = t.id 
        AND k.keyno = 6
        AND k.id = t.id)
    AS 'column6',

(SELECT c.name FROM syscolumns c INNER JOIN sysindexkeys k 
    ON k.indid = i.indid 
        AND c.colid = k.colid 
        AND c.id = t.id 
        AND k.keyno = 7
        AND k.id = t.id)
    AS 'column7',

(SELECT c.name FROM syscolumns c INNER JOIN sysindexkeys k 
    ON k.indid = i.indid 
        AND c.colid = k.colid 
        AND c.id = t.id 
        AND k.keyno = 8 
        AND k.id = t.id)
    AS 'column8',

(SELECT c.name FROM syscolumns c INNER JOIN sysindexkeys k 
    ON k.indid = i.indid 
        AND c.colid = k.colid 
        AND c.id = t.id 
        AND k.keyno = 9 
        AND k.id = t.id)
    AS 'column9',

(SELECT c.name FROM syscolumns c INNER JOIN sysindexkeys k 
    ON k.indid = i.indid 
        AND c.colid = k.colid 
        AND c.id = t.id 
        AND k.keyno = 10
        AND k.id = t.id)
    AS 'column10',

FROM sysobjects t
    INNER JOIN sysindexes i ON i.id = t.id 
    INNER JOIN sysobjects it ON it.parent_obj = t.id AND it.name = i.name

WHERE it.xtype = 'PK'
ORDER BY t.name, i.name

Thanks Guy.

With a slight variation I used it to find all the primary keys for all the tables.

SELECT A.Name,Col.Column_Name from 
    INFORMATION_SCHEMA.TABLE_CONSTRAINTS Tab, 
    INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE Col ,
    (select NAME from dbo.sysobjects where xtype='u') AS A
WHERE 
    Col.Constraint_Name = Tab.Constraint_Name
    AND Col.Table_Name = Tab.Table_Name
    AND Constraint_Type = 'PRIMARY KEY '
    AND Col.Table_Name = A.Name

Below query will list primary keys of particular table:

SELECT DISTINCT
    CONSTRAINT_NAME AS [Constraint],
    TABLE_SCHEMA AS [Schema],
    TABLE_NAME AS TableName
FROM
    INFORMATION_SCHEMA.KEY_COLUMN_USAGE
WHERE
    TABLE_NAME = 'mytablename'

If you are looking to do your own ORM or generate code from a given table, then this might be what you are looking form:

declare @table varchar(100) = 'mytable';

with cte as
(
    select 
        tc.CONSTRAINT_SCHEMA
        , tc.CONSTRAINT_TYPE
        , tc.TABLE_NAME
        , ccu.COLUMN_NAME
        , IS_NULLABLE
        , DATA_TYPE
        , CHARACTER_MAXIMUM_LENGTH
        , NUMERIC_PRECISION
    from 
        INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc 
        inner join INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE ccu on tc.TABLE_NAME=ccu.TABLE_NAME  and tc.TABLE_SCHEMA=ccu.TABLE_SCHEMA
        inner join information_schema.COLUMNS c on ccu.COLUMN_NAME=c.COLUMN_NAME and ccu.TABLE_NAME=c.TABLE_NAME and ccu.TABLE_SCHEMA=c.TABLE_SCHEMA
    where 
        tc.table_name=@table
        and 
        ccu.CONSTRAINT_NAME=tc.CONSTRAINT_NAME
    union 
    select TABLE_SCHEMA,'COLUMN', TABLE_NAME, COLUMN_NAME, IS_NULLABLE, DATA_TYPE,CHARACTER_MAXIMUM_LENGTH, NUMERIC_PRECISION from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME=@table
    and COLUMN_NAME not in (select COLUMN_NAME from INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE where TABLE_NAME = @table)
)
select 
    cast(iif(CONSTRAINT_TYPE='PRIMARY KEY',1,0) as bit) PrimaryKey
    ,cast(iif(CONSTRAINT_TYPE='FOREIGN KEY',1,0) as bit) ForeignKey
    ,cast(iif(CONSTRAINT_TYPE='COLUMN',1,0) as bit) NotKey
    ,COLUMN_NAME
    ,cast(iif(is_nullable='NO',0,1) as bit) IsNullable
    , DATA_TYPE
    , CHARACTER_MAXIMUM_LENGTH
    , NUMERIC_PRECISION 
from 
    cte 
order by 
    case CONSTRAINT_TYPE 
        when 'PRIMARY KEY' then 1 
        when 'FOREIGN KEY' then 2 
        else 3 end
    , COLUMN_NAME

Here is what the result would look like:

    <table cellspacing=0 border=1>
     <tr>
      <td style=min-width:50px>PrimaryKey</td>
      <td style=min-width:50px>ForeignKey</td>
      <td style=min-width:50px>NotKey</td>
      <td style=min-width:50px>COLUMN_NAME</td>
      <td style=min-width:50px>IsNullable</td>
      <td style=min-width:50px>DATA_TYPE</td>
      <td style=min-width:50px>CHARACTER_MAXIMUM_LENGTH</td>
      <td style=min-width:50px>NUMERIC_PRECISION</td>
     </tr>
     <tr>
      <td style=min-width:50px>1</td>
      <td style=min-width:50px>0</td>
      <td style=min-width:50px>0</td>
      <td style=min-width:50px>LectureNoteID</td>
      <td style=min-width:50px>0</td>
      <td style=min-width:50px>int</td>
      <td style=min-width:50px>NULL</td>
      <td style=min-width:50px>10</td>
     </tr>
     <tr>
      <td style=min-width:50px>0</td>
      <td style=min-width:50px>1</td>
      <td style=min-width:50px>0</td>
      <td style=min-width:50px>LectureId</td>
      <td style=min-width:50px>0</td>
      <td style=min-width:50px>int</td>
      <td style=min-width:50px>NULL</td>
      <td style=min-width:50px>10</td>
     </tr>
     <tr>
      <td style=min-width:50px>0</td>
      <td style=min-width:50px>1</td>
      <td style=min-width:50px>0</td>
      <td style=min-width:50px>NoteTypeID</td>
      <td style=min-width:50px>0</td>
      <td style=min-width:50px>int</td>
      <td style=min-width:50px>NULL</td>
      <td style=min-width:50px>10</td>
     </tr>
     <tr>
      <td style=min-width:50px>0</td>
      <td style=min-width:50px>0</td>
      <td style=min-width:50px>1</td>
      <td style=min-width:50px>Body</td>
      <td style=min-width:50px>0</td>
      <td style=min-width:50px>nvarchar</td>
      <td style=min-width:50px>-1</td>
      <td style=min-width:50px>NULL</td>
     </tr>
     <tr>
      <td style=min-width:50px>0</td>
      <td style=min-width:50px>0</td>
      <td style=min-width:50px>1</td>
      <td style=min-width:50px>DisplayOrder</td>
      <td style=min-width:50px>0</td>
      <td style=min-width:50px>int</td>
      <td style=min-width:50px>NULL</td>
      <td style=min-width:50px>10</td>
     </tr>
    </table>
    

If Primary Key and type needed, this query may be useful:

SELECT L.TABLE_SCHEMA, L.TABLE_NAME, L.COLUMN_NAME, R.TypeName
FROM(
    SELECT COLUMN_NAME, TABLE_NAME, TABLE_SCHEMA
    FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
    WHERE OBJECTPROPERTY(OBJECT_ID(CONSTRAINT_SCHEMA + '.' + QUOTENAME(CONSTRAINT_NAME)), 'IsPrimaryKey') = 1
)L
LEFT JOIN (
    SELECT
    OBJECT_NAME(c.OBJECT_ID) TableName ,c.name AS ColumnName ,t.name AS TypeName
    FROM sys.columns AS c
    JOIN sys.types AS t ON c.user_type_id=t.user_type_id
)R ON L.COLUMN_NAME = R.ColumnName AND L.TABLE_NAME = R.TableName

For a comma separated list of primary key columns for a given TableName and Schema:

Select distinct SUBSTRING ( stuff(( select distinct ',' + [COLUMN_NAME] 
                                    from INFORMATION_SCHEMA.KEY_COLUMN_USAGE  
                                    where OBJECTPROPERTY(OBJECT_ID(CONSTRAINT_SCHEMA + '.' + QUOTENAME(CONSTRAINT_NAME)), 'IsPrimaryKey') = 1  
                                    AND TABLE_NAME = 'TableName' AND TABLE_SCHEMA = 'Schema'  
                                    order by 1 FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'),1,0,'' ) 
                            ,2,9999) 

Give this a try:

SELECT
    CONSTRAINT_CATALOG AS DataBaseName,
    CONSTRAINT_SCHEMA AS SchemaName,
    TABLE_NAME AS TableName,
    CONSTRAINT_Name AS PrimaryKey
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS 
WHERE CONSTRAINT_TYPE = 'Primary Key' and Table_Name = 'YourTable'

May I suggest a more accurate simple answer to the original question below

SELECT 
KEYS.table_schema, KEYS.table_name, KEYS.column_name, KEYS.ORDINAL_POSITION 
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE keys
INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS CONS 
    ON cons.TABLE_SCHEMA = keys.TABLE_SCHEMA 
    AND cons.TABLE_NAME = keys.TABLE_NAME 
    AND cons.CONSTRAINT_NAME = keys.CONSTRAINT_NAME
WHERE cons.CONSTRAINT_TYPE = 'PRIMARY KEY'

Notes:

  1. Some of the answers above are missing a filter for just primary key columns!
  2. I'm using below in a CTE to join to a larger column listing to provide the metadata from a source to feed BIML generation of staging tables and SSIS code

I found this from my friend, very effective if you are looking for all the table's primary keys under particular schema.

SELECT tc.constraint_name AS IndexName,tc.table_name AS TableName,tc.table_schema
AS SchemaName,kc.column_name AS COLUMN_NAME
FROM information_schema.table_constraints tc,information_schema.key_column_usage kc
WHERE tc.constraint_type = 'PRIMARY KEY' AND kc.table_name = tc.table_name AND kc.table_schema = tc.table_schema
AND kc.constraint_name = tc.constraint_name AND tc.table_schema='<SCHEMA_NAME>'

Probably the simplest solution :)

EXEC sp_pkeys YourTable

If you need it in Oracle it is so simple.

SELECT `Constraint_Name`
  FROM `All_Constraints`
 WHERE `Constraint_Type` = `'P'`
   AND `Owner` = `'your schema here';`
Related