2015-01-11 3 views
0

Я пытаюсь создать триггер, чтобы проверить, что сумма вставок трех разных типов древесины должна быть равна 10 (10 представляют 100%) в определенной «рабочей области» в таблице, называемой SpaceMixes. «Процент» - это столбец, в котором процент деревянного типа хранится в определенном рабочем пространстве (типы древесины называются «H», «P» или «F»).триггер для вставки для проверки суммы

Эти рабочие пространства определяются их первичным ключом комбинации (AreaNr, SpaceNr), хотя весь PK для SpaceMixes (AreaNr, SpaceNr, WoodType). Триггер ниже проверяет, что сумма может быть только 10 в одном рабочем пространстве, но проблема в том, что первое значение также должно быть 10 с этим кодом. Но я хотел бы иметь возможность вставить как «2 + 5 + 3» для рабочего пространства, и он не должен допускать, например, 2 + 5 + 5, так как это превысит сумму 10 в общей сложности для этого рабочего пространства (см. желаемый результат).

Текущий триггер Я использую:

ALTER TRIGGER trg_Sum ON SpaceMixes 
FOR INSERT AS 

DECLARE @sum INT 

SELECT @sum = sum(SpaceMixes.Percentage) 
FROM inserted, SpaceMixes 
WHERE inserted.AreaNr = SpaceMixes.AreaNr AND inserted.SpaceNr = SpaceMixes.SpaceNr 
GROUP BY inserted.AreaNr 

IF NOT (@sum = 10) 

BEGIN 
RAISERROR ('The sum of the percentages must be 10 for each work space!',16, 1) 
ROLLBACK TRANSACTION 
END 

DESIRED РЕЗУЛЬТАТ: Первые две вставки ниже должны работать нормально, но я хотел бы триггер должен быть активирован на третьем, так как процент «5 'будет превосходить сумму 10 (5 + 3 + 5 = 13) для рабочего пространства (2, 3). Я другие слова, третья вставка должна быть разрешена только, если данный процент был 2 вместо 5

INSERT INTO SpaceMixes VALUES (2, 3, 'P', 5) 
INSERT INTO SpaceMixes VALUES (2, 3, 'F', 3) 
INSERT INTO SpaceMixes VALUES (2, 3, 'H', 5) 

ли кто-нибудь знает, как исправить этот триггер, чтобы сделать эту сумму работу?

ответ

2

Прежде всего, вы должны включать в себя CHECK constaint в SpaceMixes таблице таким образом, чтобы гарантировать, что ни одна запись никогда не превышает максимальное значение в процентах:

ALTER TABLE SpaceMixes ADD CONSTRAINT CHK_Percentage CHECK ([Percentage] <=10) 

Этот триггер:

CREATE TRIGGER [dbo].[trg_Sums] ON [dbo].[SpaceMixes] 
    AFTER UPDATE, INSERT 
AS 

-- First check Work spaces having only two records (not yet complete). 
-- These should have a percentage not greater than 10, allowing for the insertion of 
-- the last work space member. 
IF EXISTS (
    SELECT TOP 1 NULL 
    FROM (
     SELECT SUM(Percentage) AS TotalPercentage 
     FROM SpaceMixes 
     WHERE AreaNr = (SELECT AreaNr FROM inserted) AND 
      SpaceNr = (SELECT SpaceNr FROM inserted) 
     GROUP BY AreaNr, SpaceNr 
     HAVING COUNT(*) = 2) t 
    WHERE t.TotalPercentage > 10 
) 
BEGIN 
    RAISERROR ('The sum of the percentages cannot be greater than 10 for any sub-workspace!',16, 1) 
    ROLLBACK TRANSACTION 
END 

-- Now check Work spaces having exactly three records (i.e. complete workspace). 
-- These should have a total percentage equal to 10. 
IF EXISTS (
    SELECT TOP 1 NULL 
    FROM (SELECT SUM(Percentage) AS TotalPercentage 
     FROM SpaceMixes 
     WHERE AreaNr = (SELECT AreaNr FROM inserted) AND 
       SpaceNr = (SELECT SpaceNr FROM inserted) 
     GROUP BY AreaNr, SpaceNr 
     HAVING COUNT(*) = 3) t 
    WHERE t.TotalPercentage <> 10  
) 
BEGIN 
    RAISERROR ('The sum of the percentages must be 10 for each work space!',16, 1) 
    ROLLBACK TRANSACTION 
END 

должен сделать работу. Обратите внимание, что кроме вы должны определить триггер также для UPDATE.

Вставив эти две записи:

INSERT INTO SpaceMixes VALUES (2, 3, 'P', 5) 
INSERT INTO SpaceMixes VALUES (2, 3, 'F', 3) 

оба из следующих INSERT и UPDATE запросов вызовет ошибку:

INSERT INTO SpaceMixes VALUES (2, 3, 'H', 5) -- SUM = 13 
INSERT INTO SpaceMixes VALUES (2, 3, 'H', 1) -- SUM = 9 

-- UPDATE SpaceMixes after inserting a percentage of 2 for WOOD TYPE = 'H' 
UPDATE SpaceMixes 
SET Percentage = 6 
WHERE AreaNr = 2 AND SpaceNr =3 And WoodType = 'F' 
+0

@ eqinna Это просто быстрый способ обозначить, что по запросу возвращается хотя бы одна запись. Просто выполните «SELECT TOP 1 NULL FROM SpaceMixes», когда SpaceMixes содержит хотя бы одну запись и когда SpaceMixes пуст, и вы увидите. –

+0

@eqinna Относительно легко это исправить. –

+0

@eqinna 'HAVING COUNT (*) = 3' гарантирует, что будут проверены только ** полные рабочие пространства ** –

0

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

Вот компромисс, который вы можете рассмотреть. Вы можете иметь все три значения в той же строке:

create table SpaceMixes(
    AreaNr int not null, 
    SpaceNr int not null, 
    P_Wood int, 
    F_Wood int, 
    H_Wood int, 
    ... 
    constraint PK_SpaceMixes primary key(AreaNr, SpaceNr), 
    constraint CK_Exactly10Required check(IsNull(P_Wood + F_Wood + H_Wood, 10) = 10), 
    constraint CK_Total10Exceeded check(IsNull(P_Wood, 0) + IsNull(F_Wood, 0) + IsNull(H_Wood, 0) <= 10), 
); 

Преимущество заключается в том, что большинство из того, что вы хотите, это достижимо с помощью обычных проверочных ограничений. Ограничение CK_Exactly10Required будет обеспечивать соблюдение правила, которое, если все три поля имеют значение, должно быть равно 10. Ограничение CK_Total10Exceeded будет обеспечивать соблюдение правила, независимо от того, сколько значений определено, сумма не может превышать 10. Вы можете добавить другие ограничения (например, никакое значение не может быть отрицательным) по мере необходимости для уточнения проверки. В любом случае, для этой цели не нужны триггеры.

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

Редактировать: Даже если вы не хотите или не можете денормализовать, я подумал, что могу представить свой собственный триггер для вашего рассмотрения. Вам действительно не нужно отдельное контрольное ограничение, чтобы проверить, что каждое значение равно 10 или меньше, поскольку триггер также поймает это условие. Я бы порекомендовал контрольное ограничение, чтобы поймать отрицательные значения. Это также может быть помещено в триггер, но проверки должны выполняться как можно более низким уровнем.

На спусковом крючке. Это будет работать для вложений и Обновления. Нет необходимости в триггере Delete, так как нет действия удаления, которое закончится с недопустимой суммой. Как вы можете видеть в запросе, он просто проверяет, что для трех записей сумма должна быть ровно 10, иначе она должна быть десять или меньше. Просто проверьте наличие каких-либо отклонений и поднимите ошибку, если она найдена.

create trigger SpaceMixes_IU 
on SpaceMixes 
after insert, update as 
declare 
    @Result int; 

with 
KeyList as(
    select distinct AreaNr, SpaceNr 
    from inserted 
) 
select @Result = case when Count(*) = 3 
      then case Sum(sm.Percentage) when 10 then 0 else 1 end 
     else case when Sum(sm.Percentage) <= 10 then 0 else 1 end 
     end 
from SpaceMixes sm 
join KeyList  kl 
    on kl.AreaNr = sm.AreaNr 
    and kl.SpaceNr = sm.SpaceNr 
group by sm.AreaNr, sm.SpaceNr; 

if @Result > 0 begin 
    Rollback; 
    RaisError('Workspace percentages not valid!', 16, 0); 
end; 
+0

Типы дерева «P», «F» и «H» не должны быть общими атрибутами в таблице SpaceMixes. Это должно уменьшить избыточность. Поэтому лучше хранить типы дерева в отдельной таблице, как сейчас, и использовать их как часть первичного ключа, так и внешние ключи в таблице SpiceMixes. – eqinna

+0

Я не знаю, скажу ли я: «не должно быть ...». Можно (и люди часто делают) делать правильные аргументы в любом случае. Тем не менее, я понял, что вы, возможно, не захотите или не сможете пройти этот маршрут, поэтому я также предложил триггер. – TommCatt

+0

В любом случае, я должен добавить, что было приятно, что вы проводили время, предлагая решение. :) – eqinna

Смежные вопросы