Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 用于插入以检查和的触发器_Sql_Sql Server_Triggers_Sum - Fatal编程技术网

Sql 用于插入以检查和的触发器

Sql 用于插入以检查和的触发器,sql,sql-server,triggers,sum,Sql,Sql Server,Triggers,Sum,我正试图创建一个触发器,以检查在一个名为SpaceMixes的表格中,特定“工作区”上三种不同木材类型的插入物总和应为10(10代表100%)“百分比”是存储在特定工作空间中的木材类型百分比的列(木材类型命名为“H”、“P”或“F”) 这些工作空间由其组合主键(AreaNr、SpaceNr)定义,即使SpaceMixes的整个主键是(AreaNr、SpaceNr、WoodType)。下面的触发器检查一个工作空间中的和是否只能为10,但问题是此代码中的第一个值也必须为10。但我希望能够为一个工作空

我正试图创建一个触发器,以检查在一个名为SpaceMixes的表格中,特定“工作区”上三种不同木材类型的插入物总和应为10(10代表100%)“百分比”是存储在特定工作空间中的木材类型百分比的列(木材类型命名为“H”、“P”或“F”)

这些工作空间由其组合主键(AreaNr、SpaceNr)定义,即使SpaceMixes的整个主键是(AreaNr、SpaceNr、WoodType)。下面的触发器检查一个工作空间中的和是否只能为10,但问题是此代码中的第一个值也必须为10。但我希望能够为一个工作空间插入“2+5+3”,并且不允许使用“2+5+5”,因为这将超过该工作空间总共10的总和(参见预期结果)

我使用的当前触发器:

改变SpaceMixes上的触发器训练和
用于插入为
声明@sum INT
选择@sum=sum(SpaceMixes.Percentage)
从插入,空格混合
其中inserted.AreaNr=SpaceMixes.AreaNr和inserted.SpaceNr=SpaceMixes.SpaceNr
按插入的区域分组。区域编号
如果不是(@sum=10)
开始
RAISERROR('每个工作空间的百分比总和必须为10!',16,1)
回滚事务
结束
预期结果: 下面的前两个插入应该可以正常工作,但我希望在第三个插入上激活触发器,因为百分比“5”将超过工作空间(2,3)的10(5+3+5=13)之和。换言之,只有当给定百分比为2而不是5时,才允许第三次插入

插入SpaceMixes值(2,3,'P',5)
插入SpaceMixes值(2,3,'F',3)
插入SpaceMixes值(2,3,'H',5)

有人知道如何修复此触发器以使此总和正常工作吗?

首先,您应该在
SpaceMixes
表中包含一个
检查
常数,以确保没有任何记录超过最大百分比值:

ALTER TABLE SpaceMixes ADD CONSTRAINT CHK_Percentage CHECK  ( [Percentage] <=10 )
以下
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'

一般来说,如果可能的话,避免将数据完整性要求分散到同一表的不同行是一个很好的数据建模规则。如您所见,它会在强制约束时产生问题

这是一个你可能需要考虑的折衷方案。您可以将所有三个值放在同一行上:

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 ),
);
创建表空间混合(
AreaNr int不为空,
SpaceNr int不为空,
普伍德国际酒店,
福伍德国际酒店,
胡伍德国际酒店,
...
约束PK_SpaceMixes主键(AreaNr,SpaceNr),
约束CK_精确10所需检查(为空(P_Wood+F_Wood+H_Wood,10)=10),

约束CK_total10超出检查(IsNull(P_-Wood,0)+IsNull(F_-Wood,0)+IsNull(H_-Wood,0)@eqinna这只是一种表示查询返回了至少一条记录的快速方法。当SpaceMixes至少包含一条记录且SpaceMixes为空时,只需执行
从SpaceMixes中选择TOP 1 NULL即可。eqinna解决此问题相对容易。@eqinna
具有COUNT(*)=3
确保只创建完整的工作区checked@eqinna你检查过我的最新更新了吗?你需要
检查
约束和辅助
如果存在
状态,这样你的触发器就完成了。我已经尝试过好几次了,它似乎起作用了。谢谢!)木材类型“P”、“F”和“H”不应该是表SpaceMixes中的公共属性。这是为了减少冗余。因此,最好像我现在这样将木材类型存储在单独的表中,并将其作为主键的一部分以及表SpaceMixes中的外键。我不知道我是否会说“不应该…”(人们经常这样做)以任何一种方式提出有效的论点。然而,我意识到你可能不想或不能走这条路,这就是为什么我也提供了一个触发器。无论如何,我应该补充一点,你花时间提供解决方案真是太好了。:)
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'
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 ),
);
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;