SQL Server 2012 - 如果我使用INSTEAD OF INSERT触发器,则不存储任何信息

时间:2014-11-15 23:13:23

标签: sql sql-server

我有一个简单的数据库,我想禁止插入RegionCode,如果代码不在我指定的边界(不是1..199而不是701..799)。这是T-SQL查询:

USE master
GO



-- Drop the database if it already exists
IF EXISTS (
    SELECT name 
        FROM sys.databases 
        WHERE name = 'MichaelUskov'
)
DROP DATABASE MichaelUskov
GO

CREATE DATABASE MichaelUskov
GO

USE MichaelUskov
GO

IF OBJECT_ID(N'Regions', 'U') IS NOT NULL
  DROP TABLE MichaelUskov.Regions


CREATE TABLE Regions
(
    ID INT PRIMARY KEY IDENTITY, 
    RegionName nvarchar(20) NOT NULL
)


IF OBJECT_ID(N'RegionCodes', 'U') IS NOT NULL
  DROP TABLE MichaelUskov.RegionCodes


CREATE TABLE RegionCodes
(
    Code int NOT NULL PRIMARY KEY,
    Region int FOREIGN KEY REFERENCES Regions(ID)
)
GO



IF OBJECT_ID(N'Cars', 'U') IS NOT NULL
  DROP TABLE MichaelUskov.Cars


CREATE TABLE Cars
(
    ID INT PRIMARY KEY IDENTITY,
    Manufacturer nvarchar(20),
    Color nvarchar(20),
    GosID nvarchar(20),
    RegionCode int FOREIGN KEY REFERENCES RegionCodes(Code),
    LastName nvarchar(20)
)
GO

IF EXISTS (SELECT * FROM dbo.sysobjects WHERE Name = 'CheckValidRegionCode' AND type = 'TR') 
    DROP TRIGGER CheckVaidRegionCode
GO


CREATE TRIGGER CheckValidRegionCode 
    ON RegionCodes 
    INSTEAD OF INSERT
AS
DECLARE @numofwrong int
BEGIN
    SET @numofwrong = (SELECT COUNT(1) FROM inserted
                      WHERE NOT(1<Code AND Code<199 OR 700<Code AND Code<799))
    if (@numofwrong != 0) 
    BEGIN
        RAISERROR(N'Неверный формат кода региона', 10, 1)
        ROLLBACK
    END
END
GO


INSERT INTO Regions VALUES(N'Москва')
INSERT INTO Regions VALUES(N'Санкт-Петербург')
INSERT INTO Regions VALUES(N'Свердловская область')
GO

INSERT INTO RegionCodes VALUES(77, 1)
INSERT INTO RegionCodes VALUES(97, 1)
INSERT INTO RegionCodes VALUES(177, 1)
INSERT INTO RegionCodes VALUES(197, 1)
INSERT INTO RegionCodes VALUES(777, 1)
INSERT INTO RegionCodes VALUES(78, 2)
INSERT INTO RegionCodes VALUES(98, 2)
INSERT INTO RegionCodes VALUES(178, 2)
INSERT INTO RegionCodes VALUES(66, 3)
INSERT INTO RegionCodes VALUES(96, 3)
INSERT INTO RegionCodes VALUES(196, 3)
GO

INSERT INTO RegionCodes VALUES(999, 3)
GO

INSERT INTO Cars VALUES(N'Volvo', N'Черный', N'А000АА', 77, N'Иванов')
INSERT INTO Cars VALUES(N'Geely', N'Белый', N'А001АА', 96, N'Петров')
INSERT INTO Cars VALUES(N'Volvo', N'Оранжевый', N'А002АА', 177, N'Сидоров')
INSERT INTO Cars VALUES(N'ZAZ', N'Зеленый', N'А003АА', 96, N'Васильев')
INSERT INTO Cars VALUES(N'Ford', N'Оранжевый', N'А000ТА', 196, N'Васечкин')
GO

INSERT INTO RegionCodes VALUES(999, 3)错误,不应插入。触发器会在此行上引发错误。但是当我从RegionCodes中选择所有行时,我发现没有行。有什么问题?

2 个答案:

答案 0 :(得分:1)

INSTEAD OF触发器完全取代了它们拦截的操作。当创建这样的触发器时,触发它执行的操作不会执行,而是执行其代码,因此INSERT本身将永远不会被运行。要更正代码,触发器必须在检查条件后再次运行INSERT

CREATE TRIGGER CheckValidRegionCode 
    ON RegionCodes 
    INSTEAD OF INSERT
AS
DECLARE @numofwrong int
BEGIN
    SET @numofwrong = (SELECT COUNT(1) FROM inserted
                      WHERE NOT(1<Code AND Code<199 OR 700<Code AND Code<799))
    IF (@numofwrong != 0) 
    BEGIN
        RAISERROR(N'Неверный формат кода региона', 10, 1)
        ROLLBACK
    END
    INSERT INTO RegionCodes (Code, Region) SELECT Code, Region FROM inserted
END

请注意,此处触发器完全覆盖了原始INSERT,因此在检查了它应该执行的条件后,它必须自己完成工作。

然而,对于这种检查触发器是一种矫枉过正和不足之处。数据库引擎为此提供了更好的选择,检查约束。这样,验证由引擎本身执行,无需触发器:

CREATE TABLE RegionCodes
(
    Code int NOT NULL PRIMARY KEY,
    Region int FOREIGN KEY REFERENCES Regions(ID) CONSTRAINT CK_RegionCodes_Code CHECK (1<Code AND Code<199 OR 700<Code AND Code<799)
)

答案 1 :(得分:0)

此查询可以满足我的需求:

USE master
GO



-- Drop the database if it already exists
IF EXISTS (
    SELECT name 
        FROM sys.databases 
        WHERE name = 'MichaelUskov'
)
DROP DATABASE MichaelUskov
GO

CREATE DATABASE MichaelUskov
GO

USE MichaelUskov
GO

IF OBJECT_ID(N'Regions', 'U') IS NOT NULL
  DROP TABLE MichaelUskov.Regions


CREATE TABLE Regions
(
    ID INT PRIMARY KEY IDENTITY, 
    RegionName nvarchar(20) NOT NULL
)


IF OBJECT_ID(N'RegionCodes', 'U') IS NOT NULL
  DROP TABLE MichaelUskov.RegionCodes


CREATE TABLE RegionCodes
(
    Code int NOT NULL PRIMARY KEY,
    Region int FOREIGN KEY REFERENCES Regions(ID)
)
GO



IF OBJECT_ID(N'Cars', 'U') IS NOT NULL
  DROP TABLE MichaelUskov.Cars


CREATE TABLE Cars
(
    ID INT PRIMARY KEY IDENTITY,
    Manufacturer nvarchar(20),
    Color nvarchar(20),
    GosID nvarchar(20),
    RegionCode int FOREIGN KEY REFERENCES RegionCodes(Code),
    LastName nvarchar(20)
)
GO

IF EXISTS (SELECT * FROM dbo.sysobjects WHERE Name = 'CheckValidRegionCode' AND type = 'TR') 
    DROP TRIGGER CheckVaidRegionCode
GO


CREATE TRIGGER CheckValidRegionCode 
    ON RegionCodes 
    INSTEAD OF INSERT
AS
DECLARE @numofwrong int
BEGIN
    SET @numofwrong = (SELECT COUNT(1) FROM inserted
                      WHERE NOT(1<Code AND Code<199 OR 700<Code AND Code<799))
    if (@numofwrong != 0) 
    BEGIN
        RAISERROR(N'Неверный формат кода региона', 10, 1)
        RETURN
    END
    ELSE
    BEGIN
        INSERT INTO RegionCodes SELECT * FROM inserted
    END
END
GO


INSERT INTO Regions VALUES(N'Москва')
INSERT INTO Regions VALUES(N'Санкт-Петербург')
INSERT INTO Regions VALUES(N'Свердловская область')
GO

INSERT INTO RegionCodes VALUES(77, 1)
INSERT INTO RegionCodes VALUES(97, 1)
INSERT INTO RegionCodes VALUES(177, 1)
INSERT INTO RegionCodes VALUES(197, 1)
INSERT INTO RegionCodes VALUES(777, 1)
INSERT INTO RegionCodes VALUES(78, 2)
INSERT INTO RegionCodes VALUES(98, 2)
INSERT INTO RegionCodes VALUES(178, 2)
INSERT INTO RegionCodes VALUES(66, 3)
INSERT INTO RegionCodes VALUES(96, 3)
INSERT INTO RegionCodes VALUES(196, 3)
GO

INSERT INTO RegionCodes VALUES(999, 3)
GO

INSERT INTO Cars VALUES(N'Volvo', N'Черный', N'А000АА', 77, N'Иванов')
INSERT INTO Cars VALUES(N'Geely', N'Белый', N'А001АА', 96, N'Петров')
INSERT INTO Cars VALUES(N'Volvo', N'Оранжевый', N'А002АА', 177, N'Сидоров')
INSERT INTO Cars VALUES(N'ZAZ', N'Зеленый', N'А003АА', 96, N'Васильев')
INSERT INTO Cars VALUES(N'Ford', N'Оранжевый', N'А000ТА', 196, N'Васечкин')
GO