我在这里寻求高级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'。
我的SQL编程仍然是新手。 任何帮助将不胜感激。
答案 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