处理触发器的不同方法

时间:2017-12-11 10:28:27

标签: sql sql-server triggers

第一张表示Nurse,第二张表示她负责的MedicalRecords。您可以在Nurse表中的MedicalRecords表中找到IDNurse表中foreign key列为denormalization的两列,而第二列是Nurse: ┌─────────┬───────────┐ │ IDNurse │ NurseName │ ├─────────┼───────────┤ │ 1 │ name1 │ │ 2 │ name2 │ └─────────┴───────────┘ MedicalRecords: ┌──────┬────────────┬──────┬─────────┬───────────┐ │ IDMR │ Date │ Note │ IDNurse │ NurseName │ ├──────┼────────────┼──────┼─────────┼───────────┤ │ 1 │ 12/11/2017 │ / │ 1 │ name1 │ └──────┴────────────┴──────┴─────────┴───────────┘

MedicalRecords

我在NurseName上实施了两个触发器,其中一个在插入新记录时获得IDNurse(根据NurseName),另一个触发器限制更新ALTER TRIGGER [dbo].[RESTRICT] ON [dbo].[MedicalRecords] AFTER UPDATE AS IF UPDATE (NurseName) BEGIN SET NOCOUNT ON; RAISERROR('You are not allowed to update that column from this table!', 16, -1) ROLLBACK TRAN RETURN END 柱:

Nurse

NurseName上实施了一个触发器,在更新列MedicalRecords时触发并更新ALTER TRIGGER [dbo].[NurseName-UPDATE] ON [dbo].[Nurse] AFTER UPDATE AS IF UPDATE (NurseName) BEGIN SET NOCOUNT ON; ALTER TABLE DBO.MedicalRecords DISABLE TRIGGER RESTRICT UPDATE DBO.MedicalRecords SET NurseName = (SELECT NurseName FROM Nurse WHERE MedicalRecords.IDNurse = (SELECT IDNurse FROM Nurse)) ALTER TABLE DBO.MedicalRecords ENABLE TRIGGER RESTRICT END 中的相同列:

NurseName
  1. Nurse中更新RESTRICT而不在MedicalRecords中禁用和启用RESTRICT触发器时,是否还有其他方法可以完成RESTRICT的更新?
  2. 是否有任何情况如果在其中间发生某些问题,finally触发器会保持禁用状态?我如何确保始终启用try-catch触发器,例如List<SomeType> ItemsList {get { return classInstance.ItemsList;} set {... 中的List<SomeType> itemsList = classInstance.ItemsList; List<Wrapper> wrapperList = itemsList.Select(x => new Wrapper {Item = x, IsSelected = ... 阻止?

1 个答案:

答案 0 :(得分:1)

我同意,这不是非规范化的正确例子。这是非规范化名称的无效数据库设计。

你仍然有一个有趣的问题。你的问题都很好。

你的第二个问题很简单,我试着稍后找到第一个问题的解决方案。

  

是否存在中间发生某些问题的情况   它,RESTRICT触发器会保持禁用状态吗?我怎么能确定   RESTRICT触发器始终处于启用状态,例如最终   在try-catch中阻止?

你可以在proc

中开始尝试和交易
CREATE TABLE dbo.triggerTest ( rowId INT IDENTITY PRIMARY KEY, someData VARCHAR(50) DEFAULT NEWID() )
GO

ALTER TRIGGER dbo.itrg_triggerTest  ON dbo.triggerTest
FOR INSERT
AS

--SELECT @@PROCID, OBJECT_NAME( @@PROCID ) 

--SELECT OBJECT_SCHEMA_NAME( parent_id ) + '.' + OBJECT_NAME( parent_id ) tableName FROM sys.triggers WHERE object_id = @@PROCID
select 1/0
GO





ALTER proc test1
as
begin
begin try
begin tran
INSERT INTO dbo.triggerTest DEFAULT VALUES
COMMIT
end try
begin catch
print 'hi'
 IF @@TRANCOUNT > 0
ROLLBACK
end catch
end
go

exec test1

select * from triggerTest

DROP TABLE dbo.triggerTest
GO

由于触发器内部除以0错误,因此proc catch块将始终触发,然后您可以启用触发器代码。因为您在catch块中启用了触发器,所以会发生错误。

Second solution是删除触发器的想法,并在更新级联上删除时定义外键约束。 为此你必须在护士桌上的nurseid和nursename上定义复合主键,这可能是你无法接受的。

否则它可以正常工作

见,

create table nurse(IDNurse int identity(1,1) ,NurseName varchar(50) not null
,primary key (IDNurse,NurseName))
insert into nurse VALUES
('name1'),('name2')

create table MedicalRecords(IDMR int identity(1,1),Dates date, Note varchar(50),IDNurse int ,NurseName varchar(50)
,FOREIGN KEY (IDNurse,NurseName) REFERENCES nurse(IDNurse,NurseName) ON DELETE CASCADE ON UPDATE CASCADE  )
insert into MedicalRecords VALUES
('12/11/2017','/',1,'name1')

--drop table MedicalRecords

--According to current example

--this fail
--update MedicalRecords set NurseName='name3',IDNurse=1
--this pass
--update MedicalRecords set NurseName='name1',IDNurse=1
--this pass
--update MedicalRecords set NurseName='name2',IDNurse=2
--this fail
--update MedicalRecords set NurseName='name22',IDNurse=2

--this pass and medicalrecord is auto updated
--update Nurse set NurseName='name3' where IDNurse=1

--disadvantage primary key (IDNurse,NurseName) may not be accepttable

Is there any other way to accomplish updating of NurseName when it is updated in Nurse without disabling and enabling RESTRICT trigger in MedicalRecords?

我认为你可以使用TRIGGER_NESTLEVEL()来做到这一点。我对使用它并不是很专业,所以要对它进行测试。

删除上一个示例,删除表,删除触发器。

--drop table nurse
create table nurse(IDNurse int identity(1,1) ,NurseName varchar(50) not null
)
insert into nurse VALUES
('name1'),('name2')

create table MedicalRecords(IDMR int identity(1,1),Dates date, Note varchar(50),IDNurse int ,NurseName varchar(50)
 )
insert into MedicalRecords VALUES
('12/11/2017','/',1,'name1')

--drop table MedicalRecords

CREATE  TRIGGER [dbo].[NurseName-UPDATE] 
   ON  [dbo].[Nurse]
   AFTER UPDATE AS 
   IF UPDATE (NurseName)
BEGIN
    SET NOCOUNT ON;
    --ALTER TABLE DBO.MedicalRecords DISABLE TRIGGER RESTRICT
    UPDATE MR
    set NurseName=i.NurseName
    from DBO.MedicalRecords MR
    inner join inserted i on mr.IDNurse=i.IDNurse

    --ALTER TABLE DBO.MedicalRecords ENABLE TRIGGER RESTRICT
END
GO

CREATE TRIGGER [dbo].[RESTRICT]
   ON  [dbo].[MedicalRecords] 
   AFTER UPDATE
AS 
IF UPDATE (NurseName)
BEGIN
    SET NOCOUNT ON;

    if((SELECT TRIGGER_NESTLEVEL( OBJECT_ID('NurseName-UPDATE')))=0)
    BEGIN
    --SELECT OBJECT_SCHEMA_NAME( parent_id ) + '.' + OBJECT_NAME( parent_id ) tableName FROM sys.triggers 
    --WHERE object_id = @@PROCID
    RAISERROR('You are not allowed to update that column from this table!', 16, -1)
    ROLLBACK TRAN
    END
    RETURN
END
GO

准备测试!!

--This one fail
update MedicalRecords set NurseName='name1',IDNurse=1

-- This one pass
update Nurse set NurseName='name3' where IDNurse=1
  

第四个解决方案,

这个是完美的,简单的,并且适用于所有版本。这里的想法是允许更新MedicalRecord表,但如果该记录在护士表中不存在则回滚。

--drop table nurse
create table nurse(IDNurse int identity(1,1) ,NurseName varchar(50) not null
)
insert into nurse VALUES
('name1'),('name2')


create table MedicalRecords(IDMR int identity(1,1),Dates date, Note varchar(50),IDNurse int ,NurseName varchar(50)
 )
insert into MedicalRecords VALUES
('12/11/2017','/',1,'name1')

--drop table MedicalRecords

CREATE  TRIGGER [dbo].[NurseName-UPDATE] 
   ON  [dbo].[Nurse]
   AFTER UPDATE AS 
   IF UPDATE (NurseName)
BEGIN
    SET NOCOUNT ON;

    UPDATE MR
    set NurseName=i.NurseName
    from DBO.MedicalRecords MR
    inner join inserted i on mr.IDNurse=i.IDNurse


END
GO

ALTER TRIGGER [dbo].[RESTRICT]
   ON  [dbo].[MedicalRecords] 
   AFTER UPDATE
AS 
IF UPDATE (NurseName)
BEGIN
    SET NOCOUNT ON;

    if not exists(SELECT nursename from dbo.nurse n where exists(select nursename from inserted i 
    where n.nursename=i.nursename and n.IDNurse=i.IDNurse ))
    BEGIN

    RAISERROR('You are not allowed to update that column from this table!', 16, -1)
    ROLLBACK TRAN
    END
    RETURN
END
GO

--This one pass
update MedicalRecords set NurseName='name1'where IDNurse=1

--This one fail
update MedicalRecords set NurseName='name1' where IDNurse=2

--this one fail
update MedicalRecords set NurseName='name2'
相关问题