第一张表示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
Nurse
中更新RESTRICT
而不在MedicalRecords
中禁用和启用RESTRICT
触发器时,是否还有其他方法可以完成RESTRICT
的更新?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 = ...
阻止?答案 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'