监视跨越多个相关表的记录中的更改

时间:2014-07-23 11:58:35

标签: sql

我在这里寻求高级SQL专家的帮助。

我有5个相关表:表A + B + C + D + E,其中表A存在于B,C,D,E中作为外键。

我还有一个大表,它结合了所有5个表中的所有行,即: '表A + B + C + D + E'。

我正在寻找一种方法来监控5个表中任何一个表中的变化并插入整个相关记录(A + B + C + D + E),无论是UPDATES还是INSERTS到大表中:'table A + B + C + D + E'。

enter image description here

我的SQL编程仍然是新手。 任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:0)

好的,没有人在一天多的时间里碰到它,这与我在触发器和交易之间的互动中所做的一些探索有关,所以我会调整我的一个实验(希望)让它适用你的问题。

但首先,我不清楚你到底在做什么,所以我会做一些假设。为了清楚起见,我会陈述它们。

1)我假设您已经考虑过使用Big Table的视图,并因某些原因拒绝了。如果你还没有,现在就停下来看看,这通常是这种情况的最佳解决方案。您甚至可以通过为其编写INSTEAD OF触发器来基于多个表进行更新。它始终具有最新数据,没有任何时序问题或逻辑问题。

2)我假设您希望更改APPENDED到您的大表,正如您所说,虽然更改UPDATE应该不难。请记住,我的解决方案是APPEND。

3)我假设你不关心删除,因为你特别提到了UPDATES和INSERTS

4)我认为,当你说外键关系时,你指的是一个真实的正式关系,而且这是一对一的关系。

5)我假设您需要实时更新Big Table,如果您只是标记了脏行并且根据它进行了每小时或每晚更新,您可能会获得更强大的解决方案。

尝试解释解决方案很难,因此我将为您提供一个模板,您可以使用特定架构进行扩展。基本前提是将“after”触发器附加到更新并为组件表插入事件。每个触发器尝试将其更改的行与A中的匹配行组合,并将整个事物写入大表(ABC)。我只使用了3个表,你可以很容易地扩展到5个。

请注意,因为您具有外键关系并且触发器是“之后”,所以可以确保A行存在或者FK约束将回滚事务而不触发触发器。所以A是内部连接到一个已更改的表,但其他的是外部连接。

首先,创建您将使用的基表

USE [JUNK]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

SET ANSI_PADDING ON
GO
--DROP TABLE A
--DROP TABLE B
--DROP TABLE C
--DROP TABLE ABC
GO

CREATE TABLE [dbo].[A](
    [AID] [int] NOT NULL, --primary key, not enforced here to facilitate sample data entry
    [ADat] [varchar](50) NOT NULL,
) ON [PRIMARY]
GO

CREATE TABLE [dbo].[B](
    [BID] [int] NOT NULL, --primary key
    [AID] [int] NOT NULL, --foreign key on A, not enforced here to facilitate sample data entry
    [BDat] [varchar](50) NOT NULL
) ON [PRIMARY]

CREATE TABLE [dbo].[C](
    [CID] [int] NOT NULL, --primary key
    [AID] [int] NOT NULL, --foreign key on A, not enforced here to facilitate sample data entry
    [CDat] [varchar](50) NOT NULL
) ON [PRIMARY]

CREATE TABLE [dbo].[ABC](
    [abcID] [int] IDENTITY(1,1) NOT NULL,
    [AID] [int] NOT NULL, --foreign key on A, not enforced here to facilitate sample data entry
    [ADat] [varchar](50) NULL,
    [BDat] [varchar](50) NULL,
    [CDat] [varchar](50) NULL,
 CONSTRAINT [PK_ABC] PRIMARY KEY CLUSTERED 
(
    [abcID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF
        , ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

SET ANSI_PADDING OFF
GO

接下来,设置将监视组件表的触发器,并在更改一个表时更新大表

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author: Robert Sheahan
-- Create date: 2014-07-24
-- Description: Testing multiple trigger interaction in transactions,
--              logs changes to a distributed record to a big table.
-- =============================================
CREATE TRIGGER dbo.trA_IU 
   ON  dbo.A 
   AFTER INSERT,UPDATE
AS 
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;
    INSERT INTO ABC (AID, ADat, BDat, CDat)
    SELECT A.AID, ADat, BDat, CDat
    FROM A 
        LEFT OUTER JOIN B on A.AID = B.AID 
        LEFT OUTER JOIN C on A.AID = C.AID 
END
GO

-- DROP TRIGGER dbo.trB_IU
CREATE TRIGGER dbo.trB_IU 
   ON  dbo.B 
   AFTER INSERT,UPDATE
AS 
BEGIN
    SET NOCOUNT ON;
    INSERT INTO ABC (AID, ADat, BDat, CDat)
    SELECT A.AID, ADat, BDat, CDat
    FROM A
        INNER JOIN B on A.AID = B.AID 
        LEFT OUTER JOIN C on A.AID = C.AID 
END
GO

-- DROP TRIGGER dbo.trC_IU; GO;
CREATE TRIGGER dbo.trC_IU 
   ON  dbo.C 
   AFTER INSERT,UPDATE
AS 
BEGIN
    SET NOCOUNT ON;
    INSERT INTO ABC (AID, ADat, BDat, CDat)
    SELECT A.AID, ADat, BDat, CDat
    FROM A 
        INNER JOIN C on A.AID = C.AID 
        LEFT OUTER JOIN B on A.AID = B.AID 
END
GO

最后,测试并优化它以满足您的特定需求。

INSERT INTO A (AID, ADat) VALUES (1,'Hello'),(2,'Goodbye')
INSERT INTO B (BID, AID, BDat) VALUES (11,1,'new'),(12,2,'cruel')
INSERT INTO C (CID, AID, CDat) VALUES (21,1,'world!'),(22,2,'world')
UPDATE B SET BDat = 'old'    WHERE AID=1
UPDATE C SET CDat = 'planet' WHERE AID=1
SELECT * FROM ABC