【发布时间】:2014-08-03 07:52:58
【问题描述】:
我已经在互联网上搜索了一个解决方案(主要是搜索堆栈溢出),但我想不出任何办法。
这是我的目标:我有一个本地数据库,并且我已经设置了一个链接服务器到另一个数据库。我正在我的一个本地表上创建一个触发器。列值之一是酒店 ID。在链接服务器中有一个名为“Hotel”的表。此触发器的目的是检查并确保我尝试插入本地表的 HotelID 是链接服务器的 Hotel 表中存在的值。
示例:如果我想从本地向我的“存储表”中插入一个新行,我想确保我尝试插入的 HotelID 存在于我的链接服务器的“酒店”表中。如果它不存在,我想回滚事务并显示一条消息。
下面是我一直在玩的代码。我觉得我可以很接近,但我对我非常遥远的想法持开放态度。
仅供参考:IF NOT EXISTS 语句中的代码不正确。我只是对那里需要做什么感到困惑。
CREATE TRIGGER tr_trigger ON Store
AFTER Insert
AS
DECLARE @HotelID smallint = (SELECT HotelID FROM inserted)
DECLARE @query NVARCHAR(MAX) = N'SELECT * FROM OPENQUERY (test,''
SELECT HotelID FROM test.dbo.Hotel WHERE HotelID = ''''' +
CONVERT(nvarchar(15),@HotelID) +''''''')'
DECLARE @StoredResult Nvarchar(20)
BEGIN
EXEC sp_executesql @query, N'@StoredResult NVARCHAR(MAX) OUTPUT', @StoredResult =
@StoredResult OUTPUT
SELECT @StoredResult
IF NOT EXISTS (SELECT * FROM OPENQUERY (test,' SELECT HotelID FROM test.dbo.Hotel'))
BEGIN
PRINT'That HotelID does not exist. Please try again.'
ROLLBACK TRANSACTION
END
END
GO
编辑:这要感谢 marc_s 的一些建议。下面是我的新代码,可以按我的需要工作。
CREATE TRIGGER tr_trigger ON Store
AFTER Update, Insert
AS
BEGIN
IF NOT EXISTS (SELECT A.* FROM OPENQUERY (test, 'SELECT HotelID FROM test.dbo.hotel') A
INNER JOIN inserted i
ON A.HotelID = i.HotelID)
BEGIN
PRINT'Please enter a valid HotelID'
ROLLBACK TRANSACTION
END
END
GO
【问题讨论】:
-
您的触发器有 MAJOR 缺陷,因为您似乎认为它会每行调用一次 - 那是不是 b> 情况。触发器将每条语句触发一次,因此如果您的
UPDATE语句影响 25 行,您将触发触发器一次,然后Inserted和@987654325 @ 每个将包含 25 行。您的代码将在这 25 行中选择哪一行?SELECT HotelID FROM inserted- 这是不确定的。您需要重写触发器以考虑到这一点! -
这是一个插入后触发器。我可以轻松删除更新,它仍然会按照我的要求运行。这样做的目的是查看我尝试插入的 HotelID 是否存在于链接服务器表中,如果不存在,则回滚插入并显示错误。更新无关紧要,我正在删除它。而且,从插入中选择hotelid 仅选择我要插入“存储表”的HotelID。它什么都不选择。
-
我希望这能解决一些问题。我希望我能正确解释这一点。
-
你仍然假设只得到一行 - 这是不是的情况!
Inserted表 can(并且 will!)包含多行 - 您只是使用其中任意一行来进行检查。您需要完全重新架构您的触发器以处理Inserted中的多行! -
如果是这样,那我就一无所知了。它适用于我的几个 SPROCS/UDFS/触发器。也许我只是走运了。不过,我对想法非常开放。你有什么建议可以推动我实现最终目标吗?
标签: sql sql-server triggers linked-server