使用SQL Server触发器,如何在不进入无限循环的情况下保持两个相同表中的数据相同



我知道,实现这一点的最佳方法可能是对应用程序代码进行一些更改,以将所有更改保存在两个表中,但公司命令使用触发器对数据库逻辑进行更改。因此,有两个不同的数据库,都有一个名为User的表,而且它们已经有了相同的模型。我在数据库X上的User中插入/更新的内容必须插入/更新在数据库Y上的User表中,反之亦然

我设法使插入和更新触发器指向一个方向(数据库X->数据库Y(,但现在我想,当我在数据库Y上创建触发器时,会发生循环。缺少什么,或者我能做些什么来使触发循环不发生?这是我目前在其中一个数据库上创建的:


---insert trigger
USE [DATABASE_Y]
CREATE TRIGGER [dbo].[TR_USER_OnInsert] ON [dbo].[USER]
AFTER INSERT
AS 
BEGIN
SET NOCOUNT ON 
INSERT INTO [DATABASE_X].[dbo].[USER] (
usu_id,
usu_name,
usu_block,
usu_login,
usu_password
)
SELECT 
usu_id,
usu_name,
usu_block,
usu_login,
usu_password
FROM INSERTED
SET NOCOUNT OFF
END

---update trigger
USE [DATABASE_Y]
ALTER TRIGGER [dbo].[TR_USER_OnUpdate] ON [dbo].[USER]
AFTER UPDATE
AS

BEGIN

SET NOCOUNT ON 
UPDATE X
SET 
X.usu_id        = INSERTED.usu_id,
X.usu_name      = INSERTED.usu_name,
X.usu_block     = INSERTED.usu_block,
X.usu_login     = INSERTED.usu_login,
X.usu_password  = INSERTED.usu_password
FROM [DATABASE_X].[dbo].[USER] X
INNER JOIN inserted ON X.usu_login = inserted.usu_login
SET NOCOUNT OFF

END

有趣的方法。有很多不同的方法可以解决这个问题,其中大多数都比使用触发器更好。

也就是说。。。

作为触发代码的一部分,在内存中创建一些变量,然后在运行更新/插入之前对目标数据库运行select以填充它们。使用一些简单的逻辑来检查这些值是否已经设置为相同的值,并避免进入循环。

类似这样的更新触发器:

USE [DATABASE_Y]
ALTER TRIGGER [dbo].[TR_USER_OnUpdate] ON [dbo].[USER]
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON 
DECLARE @id as varchar(100)
DECLARE @name as varchar(100)
DECLARE @block as varchar(100)
DECLARE @login as varchar(100)
DECLARE @password as varchar(100)
SELECT @id = X.usu_id,
@name = X.usu_name,
@block = X.usu_block,
@login = X.usu_login,
@password = X.usu_password
FROM [DATABASE_X].[dbo].[USER] X
WHERE X.usu_login = inserted.usu_login
IF @id <> INSERTED.usu_id
OR @name <> INSERTED.usu_name
OR @block <> INSERTED.usu_block
OR @login <> INSERTED.usu_login
OR @password <> INSERTED.usu_password
BEGIN
UPDATE X
SET 
X.usu_id        = INSERTED.usu_id,
X.usu_name      = INSERTED.usu_name,
X.usu_block     = INSERTED.usu_block,
X.usu_login     = INSERTED.usu_login,
X.usu_password  = INSERTED.usu_password
FROM [DATABASE_X].[dbo].[USER] X
INNER JOIN inserted ON X.usu_login = inserted.usu_login
END
SET NOCOUNT OFF
END

我不知道你的数据类型是什么,所以我只是假设varchar(100(代表所有数据。

请确保所有列都不是NULL。如果有任何可为null的列,请确保将ISNULL逻辑添加到变量比较中。

插入触发器稍微简单一点,因为您只需要检查您试图插入的userId是否已经存在:

USE [DATABASE_Y]
CREATE TRIGGER [dbo].[TR_USER_OnInsert] ON [dbo].[USER]
AFTER INSERT
AS 
BEGIN
SET NOCOUNT ON 
IF NOT EXISTS(SELECT 1 FROM [DATABASE_X].[dbo].[USER] WHERE usu_login = INSERTED.usu_login)
BEGIN

INSERT INTO [DATABASE_X].[dbo].[USER] (
usu_id,
usu_name,
usu_block,
usu_login,
usu_password
)
SELECT 
usu_id,
usu_name,
usu_block,
usu_login,
usu_password
FROM INSERTED
END
SET NOCOUNT OFF
END

最新更新