【问题标题】:Using Trigger to keep data integrity使用触发器保持数据完整性
【发布时间】: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。它什么都不选择。
  • 我希望这能解决一些问题。我希望我能正确解释这一点。
  • 仍然假设只得到一行 - 这是不是的情况! Insertedcan(并且 will!)包含多行 - 您只是使用其中任意一行来进行检查。您需要完全重新架构您的触发器以处理Inserted 中的多行
  • 如果是这样,那我就一无所知了。它适用于我的几个 SPROCS/UDFS/触发器。也许我只是走运了。不过,我对想法非常开放。你有什么建议可以推动我实现最终目标吗?

标签: sql sql-server triggers linked-server


【解决方案1】:

怎么样:

CREATE TRIGGER tr_DataIntegrity ON Store
AFTER Update, Insert
AS
BEGIN
    IF EXISTS (
        SELECT * FROM inserted i 
        WHERE NOT EXISTS (
               SELECT A.*
               FROM OPENQUERY (TITAN_Prescott_Store, 'SELECT HotelID  FROM FARMS_Prescott.dbo.hotel') A
                WHERE A.HotelID = i.HotelID))
         BEGIN
             PRINT'Please do not enter an invalid HotelID'     
             ROLLBACK TRANSACTION
         END 
END
GO

【讨论】:

  • 这也很有效。谢谢你的想法!
  • 这里的事情是,如果你插入几行并且其中任何一行无效,它将回滚。
  • 这是一个很好的观点。就这个触发器而言,这无关紧要,但一定要牢记这一点。
猜你喜欢
  • 2013-03-26
  • 1970-01-01
  • 1970-01-01
  • 2018-06-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多