視圖本身不存儲數據。INSTEAD OF 觸發器 攔截對視圖的 DML 操作,透過
inserted/deleted虛擬表獲取變更數據,手動分發更新至底層多張基礎表。
-- 學生基本信息表
CREATE TABLE XINXIN_TAB (
姓名 NVARCHAR(10) NOT NULL,
性別 NVARCHAR(1) NOT NULL,
學號 INT NOT NULL PRIMARY KEY CLUSTERED,
班級 NVARCHAR(20) NOT NULL,
出生日期 DATE NOT NULL
)
-- 明細分數表
CREATE TABLE FENSHU_TAB (
學號 INT NOT NULL,
語文 DECIMAL(3,1) NOT NULL,
數學 DECIMAL(3,1) NOT NULL,
英語 DECIMAL(3,1) NOT NULL
)
-- 綜合分數表
CREATE TABLE ZHONGHE_TAB (
姓名 NVARCHAR(10) NOT NULL,
學號 INT NOT NULL,
總分 DECIMAL(4,1) NOT NULL,
平均分 DECIMAL(3,1) NOT NULL
)
INSERT INTO XINXIN_TAB VALUES
('李曉峰', '男', 6080, '計算機', '2013-05-03'),
('李曉峰1', '男', 6081, '計算機1', '2013-05-04'),
('李曉峰2', '男', 6082, '計算機2', '2013-05-05'),
('李曉峰3', '男', 6083, '計算機3', '2013-05-06'),
('張曉', '女', 6084, '美術', '2013-05-07')
INSERT INTO FENSHU_TAB VALUES
(6080, 99.5, 98.6, 59.2),
(6081, 93.5, 94.3, 55.8),
(6082, 96.5, 78.6, 58.5),
(6083, 99.5, 68.4, 89.2),
(6084, 99.7, 98.7, 59.4)
-- 綜合表由程式計算填充
DECLARE @i INT = 6080
WHILE @i <= 6084
BEGIN
DECLARE @zf DECIMAL(4,1), @pf DECIMAL(3,1), @xm NVARCHAR(10)
SELECT @zf = 語文+數學+英語, @pf = (語文+數學+英語)/3.0, @xm = 姓名
FROM XINXIN_TAB x JOIN FENSHU_TAB f ON x.學號=f.學號 WHERE x.學號=@i
INSERT INTO ZHONGHE_TAB VALUES (@xm, @i, @pf, @zf)
SET @i += 1
END
CREATE VIEW SHITU_FFENSHU_XINXI (姓名, 學號, 平均分, 總分, 班級, 出生日期) AS SELECT TOP 800 x.姓名, f.學號, z.平均分, z.總分, x.班級, x.出生日期 FROM XINXIN_TAB x JOIN FENSHU_TAB f ON x.學號 = f.學號 JOIN ZHONGHE_TAB z ON f.學號 = z.學號 ORDER BY f.學號
UPDATE SHITU_FFENSHU_XINXI SET 姓名='aaaaa', 平均分=111 WHERE 學號=6080
❌ 報錯:視圖 'SHITU_FFENSHU_XINXI' 不可更新,因為它修改了多個基礎表。
CREATE TRIGGER TRIGG_UPDATE ON dbo.SHITU_FFENSHU_XINXI
INSTEAD OF UPDATE
AS
BEGIN
DECLARE @姓名 NVARCHAR(10), @學號 INT, @平均分 DECIMAL(3,1), @總分 DECIMAL(4,1),
@班級 NVARCHAR(20), @出生日期 DATE
-- 遍歷 inserted 虛擬表(支援批次更新)
DECLARE cur CURSOR LOCAL FAST_FORWARD FOR
SELECT 姓名, 學號, 平均分, 總分, 班級, 出生日期 FROM inserted
OPEN cur
FETCH NEXT FROM cur INTO @姓名, @學號, @平均分, @總分, @班級, @出生日期
WHILE @@FETCH_STATUS = 0
BEGIN
-- 更新基本信息表
UPDATE XINXIN_TAB SET 姓名=@姓名, 班級=@班級, 出生日期=@出生日期 WHERE 學號=@學號
-- 更新明細分數表(學號通常不變,示例保留同步邏輯)
UPDATE FENSHU_TAB SET 學號=@學號 WHERE 學號=@學號
-- 更新綜合分數表
UPDATE ZHONGHE_TAB SET 平均分=@平均分, 總分=@總分 WHERE 學號=@學號
FETCH NEXT FROM cur INTO @姓名, @學號, @平均分, @總分, @班級, @出生日期
END
CLOSE cur; DEALLOCATE cur
END
-- 更新前 SELECT * FROM SHITU_FFENSHU_XINXI WHERE 學號=6080 -- 執行更新 UPDATE dbo.SHITU_FFENSHU_XINXI SET 姓名='liyifeng', 平均分=66.6, 總分=88.8, 班級='計算機SQLServer', 出生日期='2013-05-05' WHERE 學號=6080 -- 更新後視圖 SELECT * FROM SHITU_FFENSHU_XINXI WHERE 學號=6080 -- 驗證三張基礎表 SELECT * FROM XINXIN_TAB WHERE 學號=6080 SELECT * FROM FENSHU_TAB WHERE 學號=6080 SELECT * FROM ZHONGHE_TAB WHERE 學號=6080


-- 禁用 DISABLE TRIGGER dbo.TRIGG_UPDATE ON SHITU_FFENSHU_XINXI -- 啟用 ENABLE TRIGGER dbo.TRIGG_UPDATE ON SHITU_FFENSHU_XINXI

INSTEAD OF 觸發器讓「不可更新視圖」變為可更新,實現了單一視圖介面、多表寫入同步。核心模式:攔截 → 遍歷 inserted → 分發 UPDATE → 隱式事務保證一致性。生產環境建議配合 TRY...CATCH 記錄錯誤日誌,並嚴格控制權限。