因此,您似乎在使用多个模式来传达商店信息,同时保持对象名称一致,每个商店使用一个模式,是吗?以及某种连接/用户魔法,以便查询获得正确的视图。
如果是这样,我将介绍两个令人震惊的技巧和一个推荐的解决方案(以便您了解自己的选择)。
Egregious hack #1,假设商店视图包括基表中的所有列:
CREATE TRIGGER tr_Tenant_fluff ON AcmeBatWings.data
INSTEAD OF INSERT
AS BEGIN
DECLARE @StoreId INT
SELECT @StoreId = StoreId FROM dbo.StoreSchemas
WHERE StoreSchema = OBJECT_SCHEMA_NAME(@@PROCID)
INSERT dbo.data SELECT *, @StoreId FROM inserted
END
如果您曾经向基表添加一列,则必须更新所有商店视图以包含该列,否则触发器将中断。
Egregious hack #2,假设与 (1) 相同,只是 StoreId 包含在商店视图中:
CREATE TRIGGER tr_Tenant_fluff ON AcmeBatWings.data
INSTEAD OF INSERT
AS BEGIN
DECLARE @StoreId INT
SELECT @StoreId = StoreId FROM dbo.StoreSchemas
WHERE StoreSchema = OBJECT_SCHEMA_NAME(@@PROCID)
SELECT * INTO #inserted FROM inserted
UPDATE #inserted SET StoreId = @StoreId
INSERT dbo.data SELECT * FROM #inserted
END
hack #2 相对于hack #1 的好处是您可以使用SELECT * 定义您的商店视图,如果基表发生更改,您只需使用sp_refreshview 重新编译所有商店视图。缺点是您将插入的数据从一个中间表复制到另一个中间表,并更新第二个表。这使您的INSTEAD OF INSERT 触发器的开销增加了三倍,这在开始时已经相当昂贵。即,
-
INSTEAD OF INSERT 触发器的基本开销 -> 填充 inserted 的成本 -> x。
- 从
inserted 填充#inserted 的成本-> 大约x。
- 更新成本
#inserted -> 关于x
- 令人震惊的 hack #2 的总开销:大约 3
x
否则,最好的办法是编写触发器脚本。这是一个相当简单的过程,一旦您熟悉了系统表,您就可以调整您认为合适的触发器生成。就此而言,您还应该编写商店视图的脚本。
让您开始:
CREATE TABLE dbo.data (Name VARCHAR(10), StoreId INT)
GO
CREATE SCHEMA StoreA
GO
CREATE SCHEMA StoreB
GO
CREATE SCHEMA StoreC
GO
CREATE VIEW StoreA.data AS SELECT Name FROM dbo.data WHERE StoreId = 1
GO
CREATE VIEW StoreB.data AS SELECT Name FROM dbo.data WHERE StoreId = 2
GO
CREATE VIEW StoreC.data AS SELECT Name FROM dbo.data WHERE StoreId = 3
GO
CREATE TABLE dbo.StoreSchemas (StoreSchema SYSNAME UNIQUE, StoreId INT PRIMARY KEY)
GO
INSERT dbo.StoreSchemas VALUES ('StoreA', 1), ('StoreB', 2), ('StoreC', 3)
GO
DECLARE @crlf NCHAR(2) = NCHAR(13)+NCHAR(10)
SELECT
N'CREATE TRIGGER tr_Tenent_fluff ON '+schema_name(v.schema_id)+N'.data'+@crlf
+ N'INSTEAD OF INSERT'+@crlf
+ N'AS BEGIN'+@crlf
+ N' INSERT dbo.data ('
+ STUFF((
SELECT @crlf+N' , '+name FROM sys.columns tc
WHERE tc.object_id = t.object_id
AND (tc.name IN (SELECT name FROM sys.columns vc WHERE vc.object_id = v.object_id)
OR tc.name = N'StoreId')
ORDER BY tc.column_id
FOR XML PATH(''), TYPE).value('.','NVARCHAR(MAX)')
,5,1,N' ')+@crlf
+ N' )'+@crlf
+ N' SELECT'
+ STUFF((
SELECT @crlf+N' , '+name
+ CASE WHEN name = N'StoreId' THEN ' = '+(
SELECT CONVERT(NVARCHAR,StoreId) FROM dbo.StoreSchemas s
WHERE s.StoreSchema = SCHEMA_NAME(v.schema_id)
)
ELSE '' END
FROM sys.columns tc
WHERE tc.object_id = t.object_id
AND (tc.name IN (SELECT name FROM sys.columns vc WHERE vc.object_id = v.object_id)
OR tc.name = N'StoreId')
ORDER BY tc.column_id
FOR XML PATH(''), TYPE).value('.','NVARCHAR(MAX)')
,5,1,N' ')+@crlf
+ N' FROM inserted'+@crlf
+ N'END'+@crlf
+ N'GO'+@crlf
FROM sys.tables t
JOIN sys.views v
ON t.name = v.name
AND t.schema_id = SCHEMA_ID('dbo')
AND v.schema_id <> t.schema_id
WHERE t.name = 'data'
GO