开发者

SQL Server Keys and Index Help

Im trying to use Keys and Indexson a database and having difficulty. My requirements are as follows:

  1. I want to be able to have empty string values in the Document No column as well as values
  2. 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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜