我有一个简单的数据库,我想禁止插入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中选择所有行时,我发现没有行。有什么问题?
答案 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