non*_*ame 2 sql t-sql sql-server sql-server-2008 sql-server-2008-r2
我有两张桌子:
CREATE TABLE users
(
id int PRIMARY KEY IDENTITY,
firstname varchar(30),
lastname varchar(30),
age int
)
CREATE TABLE rejectedUsers
(
id int PRIMARY KEY IDENTITY,
firstname nvarchar,
lastname nvarchar,
age nvarchar
)
Run Code Online (Sandbox Code Playgroud)
触发器:
CREATE TRIGGER checkNumeric
ON users
INSTEAD OF INSERT
AS
INSERT INTO users SELECT firstname, lastname, age FROM inserted WHERE ISNUMERIC(age) = 1;
INSERT INTO rejectedUsers SELECT firstname, lastname, age FROM inserted WHERE ISNUMERIC(age) = 0;
-- goes fine
INSERT INTO users
VALUES
('Vlad', 'P', 21)
-- fails
INSERT INTO users
VALUES
('Chuck', 'Norris', 'abc')
Run Code Online (Sandbox Code Playgroud)
第二个语句引发了一个错误:
消息245,级别16,状态1,行1
转换将varchar值'abc'转换为数据类型int时失败.
我希望触发器执行插入rejectedUsers,有什么问题?
这是运行时错误,而不是编译器错误.在运行时将类型与基表进行比较,而不管您在一个而不是触发器中编码的任何辅助逻辑.插入的伪表是基于基表创建的,而不是基于传递给某个任意insert语句的变量类型.
我认为你不能通过简单地在它前面敲击而不是触发器来提供类型透明度.如果你想允许人们编写临时查询,他们可以在那里抛出任何数据类型,你将需要首先在中间表中使用那些容纳垃圾的数据类型.或者做大多数人所做的事:让界面强制执行数据类型.如果你使用一个接受@age参数作为INT的存储过程,它们就不能在'abc'附近的任何地方附近... ...年龄也没什么价值,因为明天或第二天它可能会改变.为什么不接受生日呢?
最后,请不要将列或变量定义为没有长度的varchar/nvarchar.在某些情况下,这些是1个字符,在其他情况下,它们是30个.要明确并告诉每个人你的真正含义.