Reputation: 2630
Is there anyway to make a secondary key in SQL?
Lets say I have a table with the columns ID, SECID1, SECID2
The key is ID
, but I also want that SECID1, SECID2
work as a key, to guarantee that I don't have 2 entries with the same SECID1
and SECID1
.
If possible, how can I do this?
Upvotes: 1
Views: 897
Reputation: 1
1) You could use an UNIQUE NONCLUSTERED constraint or an UNIQUE NONCLUSTERED index:
CREATE TABLE MyTestTable
(
ID INT NOT NULL,
A INT NOT NULL,
B INT NOT NULL,
C INT NULL,
CONSTRAINT PK_MyTestTable PRIMARY KEY(ID)
);
GO
ALTER TABLE MyTestTable
ADD CONSTRAINT UQ_MyTestTable_A_B UNIQUE NONCLUSTERED (A, B);
GO
CREATE UNIQUE NONCLUSTERED INDEX IUN_MyTestTable_A_B
ON MyTestTable(A, B);
GO
SELECT i.name, i.index_id, i.type, i.type_desc, i.is_unique, i.is_primary_key
FROM sys.indexes i
WHERE i.object_id = OBJECT_ID('dbo.MyTestTable')
GO
Results:
name index_id type type_desc is_unique is_primary_key
------------------- -------- ---- ------------ --------- --------------
PK_MyTestTable 1 1 CLUSTERED 1 1
UQ_MyTestTable_A_B 2 2 NONCLUSTERED 1 0
IUN_MyTestTable_A_B 3 2 NONCLUSTERED 1 0
Note 1: You can see that CONSTRAINT PK_MyTestTable
is created as an CLUSTERED UNIQUE INDEX
and CONSTRAINT UQ_MyTestTable_A_B UNIQUE NONCLUSTERED
is created as 'NONCLUSTERED INDEX'.
Note 2 (SQL 2008+): For me, in SQL Server 2008, then main difference between an UNIQUE NONCLUSTERED CONSTRAINT
and an UNIQUE NONCLUSTERED INDEX
is the ability to include non-indexed columns within NC index thus:
CREATE UNIQUE NONCLUSTERED INDEX IUN_MyTestTable_A_B_#_C
ON MyTestTable(A, B)
INCLUDE (C); --Nonindexed column
GO
SELECT i.name, i.index_id, i.type, i.type_desc, i.is_unique, i.is_primary_key, i.is_disabled
FROM sys.indexes i
WHERE i.object_id = OBJECT_ID('dbo.MyTestTable')
GO
Results:
name index_id type type_desc is_unique is_primary_key is_disabled
----------------------- ----------- ---- ------------ --------- -------------- -----------
PK_MyTestTable 1 1 CLUSTERED 1 1 0
UQ_MyTestTable_A_B 2 2 NONCLUSTERED 1 0 0
IUN_MyTestTable_A_B 3 2 NONCLUSTERED 1 0 0
IUN_MyTestTable_A_B_#_C 4 2 NONCLUSTERED 1 0 0
You may use CREATE UNIQUE NONCLUSTERED INDEX ... ... INCLUDE(...)
to create covering indexes and to eliminate KeyLookup or RID Lookup from execution plans.
Note 3 (SQL 2008+): Also, you may have UNIQUE NONCLUSTERED FILTERED indexes.
CREATE TABLE Invoice
(
InvoiceID INT PRIMARY KEY,
InvoiceDate DATE NOT NULL,
Total NUMERIC(8,2) NOT NULL,
--Business rule: one invoice may have only one child invoice
ParentInvoiceID INT NULL REFERENCES Invoice(InvoiceID)
);
GO
INSERT Invoice(InvoiceID, InvoiceDate, Total, ParentInvoiceID)
VALUES (1, '2011-01-01', 1000, NULL), (2, '2011-02-02', 2000, NULL);
GO
SET ANSI_WARNINGS ON;
GO
--Business rule: one invoice may have only one child invoice
CREATE UNIQUE NONCLUSTERED INDEX IUF_Invoice_ParentInvoiceID
ON Invoice(ParentInvoiceID)
WHERE ParentInvoiceID IS NOT NULL;
GO
--OK
INSERT Invoice(InvoiceID, InvoiceDate, Total, ParentInvoiceID)
VALUES (3, '2012-03-03', 1005, 1);
GO
--Error
INSERT Invoice(InvoiceID, InvoiceDate, Total, ParentInvoiceID)
VALUES (4, '2012-04-04', 1005, 1);
GO
Results:
Msg 2601, Level 14, State 1, Line 1
Cannot insert duplicate key row in object 'dbo.Invoice' with unique index 'IUF_Invoice_ParentInvoiceID'.
The statement has been terminated.
2) You could use an UNIQUE CLUSTERED constraint or an UNIQUE CLUSTERED index:
IF OBJECT_ID('dbo.MyTestTable') IS NOT NULL
DROP TABLE MyTestTable;
GO
CREATE TABLE MyTestTable
(
ID INT NOT NULL,
A INT NOT NULL,
B INT NOT NULL,
C INT NULL,
CONSTRAINT PK_MyTestTable PRIMARY KEY NONCLUSTERED(ID)
);
GO
ALTER TABLE MyTestTable
ADD CONSTRAINT UQ_MyTestTable_A_B UNIQUE CLUSTERED (A, B);
GO
SELECT i.name, i.index_id, i.type, i.type_desc, i.is_unique, i.is_primary_key, i.is_disabled
FROM sys.indexes i
WHERE i.object_id = OBJECT_ID('dbo.MyTestTable')
GO
Results:
name index_id type type_desc is_unique is_primary_key is_disabled
------------------ ----------- ---- ------------- --------- -------------- -----------
UQ_MyTestTable_A_B 1 1 CLUSTERED 1 0 0
PK_MyTestTable 2 2 NONCLUSTERED 1 1 0
Or
ALTER TABLE MyTesttable
DROP CONSTRAINT UQ_MyTestTable_A_B;
GO
CREATE UNIQUE CLUSTERED INDEX IUN_MyTestTable_A_B2
ON MyTestTable(A, B);
GO
SELECT i.name, i.index_id, i.type, i.type_desc, i.is_unique, i.is_primary_key, i.is_disabled
FROM sys.indexes i
WHERE i.object_id = OBJECT_ID('dbo.MyTestTable')
GO
Results:
name index_id type type_desc is_unique is_primary_key is_disabled
-------------------- ----------- ---- ------------ --------- -------------- -----------
IUN_MyTestTable_A_B2 1 1 CLUSTERED 1 0 0
PK_MyTestTable 2 2 NONCLUSTERED 1 1 0
Upvotes: 0
Reputation:
It is possible, here you have documentation and explanation: http://www.w3schools.com/sql/sql_unique.asp
Upvotes: 4
Reputation: 60190
You can create as many UNIQUE KEY
constraints as you like to achieve such uniqueness checks/constraints.
Upvotes: 3
Reputation: 452988
Yes, you can add a composite column unique constraint or unique index (below I use a unique constraint)
CREATE TABLE YourTable
(
ID INT PRIMARY KEY,
SECID1 INT,
SECID2 INT,
UNIQUE(SECID1,SECID2)
)
Is the surrogate ID
column definitely needed? If this is a many to many relationship table I usually just have a 2 column PK (and sometimes a unique index/constraint in reversed key order depending on queries that access that table)
Upvotes: 3