Создайте уникальное ограничение / индекс, который учитывает вторую таблицу - PullRequest
1 голос
/ 30 сентября 2019

В моей базе данных SQL Server я хочу создать уникальное ограничение, которое рассматривает вторую таблицу. Моя таблица ChargeCarrier_Storage содержит два идентификатора поля ID_ChargeCarrier и ID_Storage. Моя таблица Storage содержит два поля ID и ID_StorageType. Ограничение должно быть таким, что для типа хранения 1 в таблице ChargeCarrier_Storage должна быть только одна возможная запись. Для любого другого типа хранилища может быть бесконечное количество записей.

Мой первый подход состоял в создании некластеризованного индекса для таблицы ChargeCarrier_Storage, но это, очевидно, не работает, потому что, как икажется, вы не можете использовать соединения там.

CREATE NONCLUSTERED INDEX UQX_OnePickingStoragePerCarrier  
    ON dbo.ChargeCarrier_Storage ccs (ID_ChargeCarrier, ID_Storage)  
    INNER JOIN dbo.Storage s ON s.ID = ccs.ID_Storage
    WHERE s.ID_StorageType = 1;  
GO

Есть ли какой-нибудь простой способ сделать эту работу?

Ответы [ 2 ]

3 голосов
/ 30 сентября 2019

Вы не можете сделать это на столе, вам нужно использовать VIEW и создать там индекс:

USE Sandbox;
GO

--Create sample tables
CREATE TABLE dbo.ChargeCarrier_Storage (ID_ChargeCarrier int,
                                        ID_Storage int);
CREATE TABLE dbo.Storage (ID int,
                          ID_StorageType int);
GO
--Create Schema bound View
CREATE VIEW dbo.OnePickingStoragePerCarrier WITH SCHEMABINDING
AS
    SELECT ccs.ID_ChargeCarrier,
           s.ID AS ID_Storage
    FROM dbo.ChargeCarrier_Storage ccs
         INNER JOIN dbo.Storage s ON s.ID = ccs.ID_Storage
    WHERE s.ID_StorageType = 1;  
GO
--Create unique (clustered) index
CREATE UNIQUE CLUSTERED INDEX UQX_OnePickingStoragePerCarrier ON OnePickingStoragePerCarrier (ID_ChargeCarrier,ID_Storage);
GO

--Sample data in Storage
INSERT INTO dbo.Storage (ID,
                         ID_StorageType)
VALUES(1,1),
      (2,1),
      (3,2);
GO

--Tests
INSERT INTO dbo.ChargeCarrier_Storage (ID_ChargeCarrier,
                                       ID_Storage)
VALUES(1,1); --Works
GO

INSERT INTO dbo.ChargeCarrier_Storage (ID_ChargeCarrier,
                                       ID_Storage)
VALUES(2,1); --Works
GO

INSERT INTO dbo.ChargeCarrier_Storage (ID_ChargeCarrier,
                                       ID_Storage)
VALUES(1,2); --Works
GO

INSERT INTO dbo.ChargeCarrier_Storage (ID_ChargeCarrier,
                                       ID_Storage)
VALUES(2,1); --fails due to duplicate
GO
INSERT INTO dbo.ChargeCarrier_Storage (ID_ChargeCarrier,
                                       ID_Storage)
VALUES(1,3); --works.

INSERT INTO dbo.ChargeCarrier_Storage (ID_ChargeCarrier,
                                       ID_Storage)
VALUES(1,3); --works, as not Storage ID 1, so duplicate allowed
GO

GO

DROP VIEW dbo.OnePickingStoragePerCarrier;
DROP TABLE dbo.Storage;
DROP TABLE dbo.ChargeCarrier_Storage;
1 голос
/ 30 сентября 2019

Это также идеальный сценарий для Instead of Insert and update.

CREATE  TRIGGER trgInsteadOfStorage ON dbo.ChargeCarrier_Storage
INSTEAD OF Insert,Update
AS

BEGIN 
 SET NOCOUNT ON
 if exists(select 1 from dbo.ChargeCarrier_Storage ccs 
 INNER JOIN dbo.Storage s ON s.ID = ccs.ID_Storage
 INNER JOIN inserted i on ccs.ID_ChargeCarrier=i.ID_ChargeCarrier
 and ccs.ID_Storage=i.ID_Storage
 where s.ID_StorageType = 1
 begin
 RAISERROR('Store Type cannot be duplicate',16,1);  
 end
END

Примечание : Trigger code не протестировано и не оптимизировано. Запрос можно оптимизировать.

Зная полную структуру таблицы ChargeCarrier_Storage и понимая, как она будет использоваться при поиске и сколько там будет данных inChargeCarrier_Storage и т. Д.

Так что это зависит от ситуации, в некоторых ситуациях это может быть полезным. Например, если я создаю один Non Clustered index на dbo.ChargeCarrier_Storage (ID_ChargeCarrier), мне не нужно создавать один дополнительный уникальный индекс только для ограничения.

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