SQL Server Keys and Index Help
Im trying to use Keys and Indexson a database and having difficulty. My requirements are as follows:
- I want to be able to have empty string values in the Document No column as well as values
- The constraint should check for Unique Values based on a DatabaseID and DocumentNo ( eg you can have the same document no for 2 different database ID's)
The table is similar to this (Extra columns removed for simplicity)
RecordID (bigint)
DocumentNo (varchar(12))
DatabaseID (bigint)
So the constraint should not allow inserting or updating a record if there is already a document no for the specified document no and database ID. A blank document no should be allowed to be entered as there are multiple rows with no document no.
Is this possible? if so please could you let me know how.
EDIT: H开发者_StackOverflowere is the Query to Create the View and Constraint:
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
GO
CREATE VIEW vNoDuplicateDoNos
WITH SCHEMABINDING
AS
SELECT [PODocumentNo],[SageDatabaseID]
FROM dbo.[Order]
WHERE [PODocumentNo] <> ''
GO
--Create an index on the view.
CREATE UNIQUE CLUSTERED INDEX CI_V1_ID
ON vNoDuplicateDoNos ([PODocumentNo],[SageDatabaseID]);
GO
I am not sure about using the GUI for this, but you should use a UNIQUE INDEX with a WHERE condition (assuming you are using SQL Server 2008 or newer):
http://msdn.microsoft.com/en-us/library/ms188783.aspx
CREATE UNIQUE NONCLUSTERED INDEX UIX_TableName_DocumentNo_DatabaseID
ON dbo.TableName
(DocumentNo, DatabaseID)
WHERE DocumentNo <> ''
ON IndexesFileGroup -- omit this line if you do not have a File Group for Indexes
Also, I was not able to find an option for the WHERE condition via the GUI in the "Manage Indexes and Keys" dialog.
To be fair, this was suggested by "Martin" in a comment on the Question. I just felt it needed to be explicitly stated with an example.
IF you are using a version of SQL Server prior to 2008 (when Filtered Indexes were added), you can use a Trigger as follows:
CREATE TRIGGER dbo.TableName_PreventDuplicatesTrigger
ON dbo.TableName
AFTER INSERT, UPDATE
AS
SET NOCOUNT ON
IF (EXISTS(
SELECT 1
FROM dbo.TableName tn
INNER JOIN INSERTED ins
ON ins.DocumentNo = tn.DocumentNo
AND ins.DatabaseID = tn.DatabaseID
WHERE ins.DocumentNo <> ''
))
BEGIN
ROLLBACK TRAN
RAISERROR('Duplicate DocumentNo/DatabaseID combination detected!', 16, 1)
END
GO
The above trigger will look for any existing records that match the two fields but only if the inserted or updated DocumentNo is not empty. If found, it calls ROLLBACK which will cancel the INSERT or UPDATE statement and the RAISERROR will display a message as to what caused the ROLLBACK.
Another option when using a version of SQL Server prior to 2008 is to create an Indexed View on DocumentNo and DatabaseID while filtering out empty DocumentNo records. This was suggested by "Martin" in the comments to this Answer.
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
GO
CREATE VIEW dbo.UniqueDocumentAndDatabase
WITH SCHEMABINDING
AS
SELECT DocumentNo, DatabaseID
FROM dbo.TableName
WHERE DocumentNo <> ''
GO
CREATE UNIQUE CLUSTERED INDEX UIX_UniqueDocumentAndDatabase
ON dbo.UniqueDocumentAndDatabase
(DocumentNo, DatabaseID)
GO
Please note that the two SET options as well as the WITH SCHEMABINDING are required for Indexed Views. It is also required that SET ANSI_NULLS ON was used when creating the base table.
精彩评论