Справка по ключам и индексам SQL Server - PullRequest
0 голосов
/ 21 марта 2011

Я пытаюсь использовать Keys и Indexson базу данных и испытываю трудности.Мои требования следующие:

  1. Я хочу иметь возможность иметь пустые строковые значения в столбце Document No, а также значения
  2. Ограничение должно проверять уникальные значения на основеDatabaseID и DocumentNo (например, вы можете иметь один и тот же документ для двух разных идентификаторов базы данных)

Таблица похожа на эту (дополнительные столбцы удалены для простоты)

RecordID (bigint)
DocumentNo (varchar(12))
DatabaseID (bigint)

Итакограничение не должно позволять вставлять или обновлять запись, если для указанного документа и идентификатора базы данных уже существует документ no.Пустой документ № должен быть разрешен для ввода, так как есть несколько строк без документа №.

Возможно ли это?пожалуйста, дайте мне знать, как.

РЕДАКТИРОВАТЬ: Вот запрос для создания представления и ограничения:

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

1 Ответ

3 голосов
/ 21 марта 2011

Я не уверен в использовании графического интерфейса для этого, но вам следует использовать УНИКАЛЬНЫЙ ИНДЕКС с условием WHERE (при условии, что вы используете SQL Server 2008 или более новую версию):

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

Кроме того, мне не удалось найти параметр для условия WHERE через графический интерфейс в диалоговом окне «Управление индексами и ключами».

Чтобы быть справедливым, это было предложено «Мартином» вкомментарий к Вопросу.Я просто почувствовал, что это необходимо явно указать в примере.

Если вы используете версию SQL Server до 2008 года (когда были добавлены отфильтрованные индексы), вы можете использовать триггер следующим образом:

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

Приведенный выше триггер будет искать любые существующие записи, которые соответствуют двум полям, но только если вставленный или обновленный DocumentNo не пуст.Если он найден, он вызывает ROLLBACK, который отменяет оператор INSERT или UPDATE, а RAISERROR отображает сообщение о том, что вызвало ROLLBACK.

Другой вариант при использовании версии SQL Server до 2008 года - создатьИндексированное представление для DocumentNo и DatabaseID при фильтрации пустых записей DocumentNo.Это было предложено «Мартином» в комментариях к этому ответу.

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

Обратите внимание, что для индексированных представлений требуются два параметра SET, а также WITH SCHEMABINDING.Также необходимо, чтобы при создании базовой таблицы использовалось SET ANSI_NULLS ON.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...