所以看起來你正在使用多個模式來傳達信息存儲,同時保持對象名稱一致,每家商店瓦特/一個模式,是嗎?以及某種連接/用戶魔法,以便查詢達到正確的視圖。
如果是這樣,我提出了兩個令人震驚的黑客和一個推薦的解決方案(所以你知道你的選擇)。
程度嚴重劈#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)
INSERT dbo.data SELECT *, @StoreId FROM inserted
END
如果你曾經向基表添加一列,你必須更新所有的商店視圖才能包含該列,否則觸發器將會中斷。
性質惡劣的黑客#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
的劈#2的好處超過砍#1,你可以使用SELECT *
定義商店視圖,如果基表發生更改,則只需使用sp_refreshview
重新編譯所有商店視圖。缺點是您要將插入的數據從一箇中間表複製到另一箇中,並更新第二個表。這已經使您的INSTEAD OF INSERT
觸發器的開銷增加了三倍,這已經相當昂貴。即,INSTEAD OF INSERT
觸發的
- 基開銷 - >成本來填充
inserted
- >x
。
- 成本人口
#inserted
從inserted
→約x
。
- 成本更新
#inserted
- >約x
- 的惡劣劈#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'[email protected]
+ N'INSTEAD OF INSERT'[email protected]
+ N'AS BEGIN'[email protected]
+ 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' ')[email protected]
+ N' )'[email protected]
+ 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' ')[email protected]
+ N' FROM inserted'[email protected]
+ N'END'[email protected]
+ N'GO'[email protected]
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
你提到該系統是多租戶的;你打算爲所有的觸發器硬編碼爲'99'還是StoreId取決於誰在使用系統?另外,什麼版本的SQL Server? – LittleBobbyTables 2010-09-08 20:59:52
你是說你對每個參照相同基表的不同意見,唯一的區別是他們有不同的id過濾器? – 2010-09-08 20:59:57
您的示例中的視圖和觸發器未對齊。在視圖中,AcmeBatWings是一個模式名稱。在觸發器中,它是一個對象名稱。這是什麼?我假設一個模式名稱。它有很大的不同。 – 2010-09-09 01:45:59