我有这3张桌子:
我需要构建一个触发器:日期(" encontro")只有在两个配置文件之间存在友谊(" amizade")时才有效(" perfis& #34;。)
我创造了这个触发器,但我感到迷茫..请帮帮我
CREATE TRIGGER relaçoes_after_insert
ON encontros
INSTEAD OF insert -
as
begin
declare @idperfilA int;
declare @idperfilB int;
declare @data datetime;
declare @count int;
declare cursor_1 cursor for select * from inserted;
open cursor_1;
fetch next from cursor_1 into @idperfilA, @idperfilB, @data;
WHILE @@FETCH_STATUS = 0
BEGIN
if exists( select * from inserted i, amizade a
where i.IDPERFILA = a.IDPERFILA and i.IDPERFILB = a.IDPERFILB and GETDATE() > DATA)
RAISERROR('there isnt friendship', 16, 10);
else
insert into ENCONTROS select * from inserted;
end;
fetch next from cursor_1 into @idperfilA, @idperfilB, @data;
END
close cursor_1;
deallocate cursor_1;
答案 0 :(得分:1)
我认为更好的答案是不创建使用触发器。相反,我会在encontros
和amizade
之间创建并强制执行外键约束。
据我所知,这将导致您无需编写自己的代码来尝试重新创建数据库提供的行为。从数据库设计的角度来看,它也更容易理解。
alter table dbo.encontros
add constraint fk_amizade__encontros
foreign key (idperflia, idperflib) references dbo.amizade (idperflia, idperflib)
/* optional
on delete { no action | cascade | set null | set default } -- pick one, usual defualt is: no action
on update { no action | cascade | set null | set default } -- pick one, usual defualt is: no action
--*/*
;
有关 table constraints 的更多信息。
无动作 SQL Server数据库引擎引发错误,并回滚父表中行的删除操作。
<强> CASCADE 强> 如果从父表中删除该行,则会从引用表中删除相应的行。
SET NULL 当删除父表中的相应行时,组成外键的所有值都设置为NULL。要执行此约束,外键列必须可为空。
设置默认 当删除父表中的相应行时,组成外键的所有值都将设置为其默认值。要执行此约束,所有外键列都必须具有默认定义。如果列可以为空并且没有设置显式默认值,则NULL将成为列的隐式默认值。
根据您对@ 3N1GM4的回复:
@ 3N1GM4如果与今天之后的某个日期存在一些友谊(例如)这是一个错误,所以友谊不存在。但我不知道在这一点上是否重要。 IDPERFILA和IDPERFILB将在amizade表中匹配A和B,但我需要确保它们不相同
您可以在amizade
上创建一个检查约束,以防止将包含无效日期的行插入到表格中。
alter table dbo.amizade
add constraint chk_data_lt_getdate ([data] < get_date());
有关 check constraints 的更多信息;来自Gregory Larson的更多示例。
原始答案:
我还在等待对这个问题的一些澄清,但其中一个版本应该在正确的道路上:
create trigger relaçoes_after_insert
on encontros
instead of insert
as
begin
/* To abort when any row doesn't have a matching friendship */
if not exists (
select 1
from inserted i
where exists (
select 1
from amizade a
where a.idperfila = i.idperfila
and a.idperfilb = i.idperfilb
and getdate() > data /* not sure what this part does */
/* as @3N1GM4 pointed out,
if the position doesn't matter between idperflia and idperflib then:
where (i.idperfila = a.idperfila and i.idperfilb = a.idperfilb)
or (i.idperfila = a.idperfilb and i.idperfilb = a.idperfila)
*/
)
begin;
raiserror('there isnt friendship', 16, 10);
else
insert into encontros
select * from inserted;
end;
end;
/* To insert all rows that have a matching friendship, you could use this instead */
insert into encontros
select i.*
from inserted i
where exists (
select 1
from amizade a
where a.idperfila = i.idperfila
and a.idperfilb = i.idperfilb
and getdate() > data /* not sure what this part does */
/* as @3N1GM4 pointed out,
if the position doesn't matter between idperflia and idperflib then:
where (i.idperfila = a.idperfila and i.idperfilb = a.idperfilb)
or (i.idperfila = a.idperfilb and i.idperfilb = a.idperfila)
*/
)
end;
我在第二个选项中使用inner join
而不是exists
看到的唯一潜在问题(插入具有友谊的行并忽略那些不相关的行)是否有可能是(i.idperfila = a.idperfila and i.idperfilb = a.idperfilb) or (i.idperfila = a.idperfilb and i.idperfilb = a.idperfila)
将从返回匹配的每个条件返回插入行的重复项的问题。