Ограничение MS SQL на столбце - PullRequest
0 голосов
/ 03 декабря 2018

У меня есть таблица с названием Products, вот так она выглядит, и я пытаюсь создать ограничение для столбца [IsDefaultProductKey], чтобы при каждом добавлении к нему значения это был активный ключ продукта.

CREATE TABLE [dbo].[Products](
    [ProductId] [int] IDENTITY(1,1) NOT NULL,
    [Name] [nvarchar](64) NOT NULL,
     [IsActive] [bit] NOT NULL,
    [IsDefaultProductKey] [int] NULL,
CONSTRAINT [PK_dbo.Products] PRIMARY KEY CLUSTERED 
(
    [ProductId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[Products] ADD  CONSTRAINT [DF_products_IsActive]  DEFAULT ((1)) FOR [IsActive]
GO
ALTER TABLE [dbo].[Products]  WITH CHECK ADD  CONSTRAINT [FK_Products_Product_IsDefaultProductKey] FOREIGN KEY([IsDefaultProductKey])
REFERENCES [dbo].[Products] ([ProductId])
GO

ALTER TABLE [dbo].[Products] CHECK CONSTRAINT [FK_Products_Product_IsDefaultProductKey]
GO

Если это записи в таблице, строка 4 не должна иметь значение 1, поскольку 1 неактивно.Как я могу добавить ограничение на таблицу для этого

ProductId   Name    IsActive    IsDefaultProductKey
1            Test1  0             NULL
2            Test2  1             NULL
3            Test3  0                2
4            Test4   0             1 (Should not let me do this)

Основываясь на предложении, я создал этот UDF.Но все же не действует на 100% так, как я хочу .. Пожалуйста, предложите.

CREATE TABLE [dbo].[Products]( [ProductId] [int] IDENTITY(1,1) NOT NULL, 
[Name] [nvarchar](64) NOT NULL, 
[IsActive] [bit] NOT NULL, 
[IsDefaultProductKey] [int] NULL, 
) 
go

Create FUNCTION dbo.CheckProduct (@IsDefaultProductKey int)
RETURNS int
AS 
BEGIN
  DECLARE @retval int
    SELECT @retval = 0
    Select @retval = 1
    FROM [Products]
    WHERE ProductId = @IsDefaultProductKey and IsActive = 1 
  RETURN @retval
END;
GO
--Select CheckProduct(1)

ALTER TABLE [Products] 
  ADD CONSTRAINT chkActiveProduct 
  CHECK (IsDefaultProductKey = null or dbo.CheckProduct(IsDefaultProductKey) = 1); 
go

Ответы [ 4 ]

0 голосов
/ 04 декабря 2018

Благодаря Tab Allemnan, вот решение, которое я нашел.Работает в обе стороны.

Create FUNCTION CheckProduct (@IsDefaultProductKey int, @ProductId int, @IsActive bit)
RETURNS bit
AS 
BEGIN
BEGIN  
    DECLARE @ret bit;
    if (@IsDefaultProductKey is not NULL)
    begin  
        SELECT @ret = 1  
        FROM [Products] p   
        WHERE p.ProductID = @IsDefaultProductKey   
            AND p.IsActive = 1; 
    end
    else   -- If @IsDefaultProductKey is null
         Select @ret = 1

    If (@IsActive = 0)  -- If Product is made inactive, make sure that its not a defaultkey for any product. 
    Begin
         SELECT @ret = 0  
        FROM [Products] p   
        WHERE p.IsDefaultProductKey = @ProductId   
    End


     IF (@ret IS NULL)   
        SET @ret = 0;  
    RETURN @ret;  
END; 
END;
--Select dbo.CheckProduct (2,1,0)
GO
ALTER TABLE [Products] 
  ADD CONSTRAINT chkActiveProduct 
  CHECK (dbo.CheckProduct(IsDefaultProductKey,ProductId, IsActive)=1); 
go
0 голосов
/ 03 декабря 2018

Я не совсем понял ваши вопросы.Однако похоже, что вы хотите применить проверочное ограничение на основе значения другого столбца.Проблема, которую я вижу в вашем SQL, заключается в том, что вы применяете ограничение на уровне столбца, хотя я думаю, что вам нужно применить ограничение на уровне таблицы.Пожалуйста, смотрите образец ниже, основываясь на моем понимании вашего вопроса.

    CREATE TABLE [dbo].[Products](
    [ProductId] [int] IDENTITY(1,1) NOT NULL,
    [Name] [nvarchar](64) NOT NULL,
    [IsActive] [bit] NOT NULL,
    [IsDefaultProductKey] [int] NULL,
         CONSTRAINT ck_contraint CHECK
         (
             (IsActive = 1 AND (IsDefaultProductKey>0) ) 

         )
   )
0 голосов
/ 03 декабря 2018

Я думаю, вам нужен триггер, а не ограничение для этого.Что-то вроде:

CREATE OR ALTER TRIGGER DefaultNotActive ON [dbo].[Products]
AFTER INSERT, UPDATE
AS
IF EXISTS (SELECT *
           FROM [dbo].[Products] p 
           JOIN inserted AS i 
           ON p.[ProductId] = i.[IsDefaultProductKey] 
           WHERE p.[IsActive] = 0
          )
BEGIN
RAISERROR ('Default Product is inactive.', 16, 1);
ROLLBACK TRANSACTION;
RETURN 
END;

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

0 голосов
/ 03 декабря 2018

Вы можете использовать CHECK CONSTRAINT, который вызывает UDF, который запрашивает таблицу, чтобы узнать, активен ли ProductId, на который ссылается IsDefaultProductKey, или нет.

EDIT:
Поскольку для проверки требуется ограничениеВ обоих случаях вы должны создать UDF с параметрами для ProductId, IsActive и IsDefaultProductKey.

Внутри функции, если для IsDefaultProductKey есть значение, отличное от NULL, вам нужнозапросить таблицу, чтобы увидеть, если строка с этим ProductId является активной.Если нет, то функция должна вернуть false.

ТАКЖЕ, если параметру IsActive передано значение 0, то вам нужно проверить таблицу, чтобы убедиться, что ни одна строка не имеет IsDefaultProductKey равно значению параметра ProductId.Если есть такая строка, то функция должна вернуть false.

Но если ни один из этих случаев не произойдет, функция вернет true, и в CHECK CONSTRAINT вы просто протестируете, чтобы увидетьесли функция возвращает true.

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