(SQL 服务器触发器) 无法绑定多部分标识符
(SQL Server Trigger) The multi-part identifier could not be bound
我尝试在 table TAKES 上创建触发器,但我收到了 4 个类似的错误:
The multi-part identifier "Inserted.course_id" could not be bound.
The multi-part identifier "Inserted.sec" could not be bound.
The multi-part identifier "Inserted.semester" could not be bound.
The multi-part identifier "Inserted.year" could not be bound.
这是我的代码:
CREATE TRIGGER check_capacity ON takes FOR INSERT
AS
DECLARE @max_capacity INT;
DECLARE @current_capacity INT;
DECLARE @course_id VARCHAR;
DECLARE @sec_id VARCHAR;
DECLARE @semester VARCHAR;
DECLARE @year_ INT;
BEGIN
SET @course_id = inserted.course_id;
SET @sec_id = inserted.sec;
SET @semester = inserted.semester;
SET @year_ = inserted.year;
SET @max_capacity = dbo.get_max_capacity(@course_id,
@sec_id,
@semester,
@year_);
SET @current_capacity = dbo.get_current_capacity(@course_id,
@sec_id,
@semester,
@year_);
IF ( @max_capacity > @current_capacity ) BEGIN
print 'Insert successfully';
END
ELSE BEGIN
print 'Max capacity ' + isnull(@max_capacity, '');
print 'Current capacity ' + isnull(@current_capacity, '');
print 'The classroom is full! Choose the others';
END
END
这个触发器有一些主要缺陷:
- Not taking into account multiple (or zero) rows being inserted
PRINT
并不能阻止交易的发生,你需要THROW
。请注意,您不应在触发器中手动 ROLLBACK
,抛出异常将为您完成
- 使用标量函数,这对性能非常不利。 (我无法解决这个问题,因为我不知道他们在做什么)
- 如果@max_capacity 等于 到@current_capacity 那么它也会失败,我认为这不应该发生
- 使用没有长度的
varchar
是错误的,在某些情况下它默认为varchar(1)
CREATE TRIGGER check_capacity ON takes FOR INSERT
AS
DECLARE @max_capacity INT;
DECLARE @current_capacity INT;
IF (EXISTS (SELECT 1
FROM inserted i
WHERE dbo.get_max_capacity(i.course_id, i.sec_id, i.semester, i.year) <
dbo.get_current_capacity(i.course_id, i.sec_id, i.semester, i.year)
))
THROW 70000, N'The classroom is full! Choose the others', 0;
GO
如果您希望在错误消息中显示确切的数字,您可以这样做,但它只会显示第一个不合格行的结果:
CREATE TRIGGER check_capacity ON takes FOR INSERT
AS
DECLARE @max_capacity INT;
DECLARE @current_capacity INT;
SELECT TOP (1)
@max_capacity = v.max_capacity,
@current_capacity = v.current_capacity
FROM inserted i
CROSS APPLY (VALUES
(dbo.get_max_capacity(i.course_id, i.sec_id, i.semester, i.year),
dbo.get_current_capacity(i.course_id, i.sec_id, i.semester, i.year))
) v(max_capacity, current_capacity)
WHERE v.max_capacity < v.current_capacity;
IF (@@ROWCOUNT > 0)
BEGIN
DECLARE @msg nvarchar(150) = CONCAT('Max capacity ', @max_capacity, '
Current capacity ', @current_capacity, '
The classroom is full! Choose the others');
THROW 70000, @msg, 0;
END;
GO
这样做
SELECT @course_id = course_id,
@sec_id = sec,
@semester = semester,
@year_ = year
FROM INSERTED
然后设置其他值。
我尝试在 table TAKES 上创建触发器,但我收到了 4 个类似的错误:
The multi-part identifier "Inserted.course_id" could not be bound.
The multi-part identifier "Inserted.sec" could not be bound.
The multi-part identifier "Inserted.semester" could not be bound.
The multi-part identifier "Inserted.year" could not be bound.
这是我的代码:
CREATE TRIGGER check_capacity ON takes FOR INSERT
AS
DECLARE @max_capacity INT;
DECLARE @current_capacity INT;
DECLARE @course_id VARCHAR;
DECLARE @sec_id VARCHAR;
DECLARE @semester VARCHAR;
DECLARE @year_ INT;
BEGIN
SET @course_id = inserted.course_id;
SET @sec_id = inserted.sec;
SET @semester = inserted.semester;
SET @year_ = inserted.year;
SET @max_capacity = dbo.get_max_capacity(@course_id,
@sec_id,
@semester,
@year_);
SET @current_capacity = dbo.get_current_capacity(@course_id,
@sec_id,
@semester,
@year_);
IF ( @max_capacity > @current_capacity ) BEGIN
print 'Insert successfully';
END
ELSE BEGIN
print 'Max capacity ' + isnull(@max_capacity, '');
print 'Current capacity ' + isnull(@current_capacity, '');
print 'The classroom is full! Choose the others';
END
END
这个触发器有一些主要缺陷:
- Not taking into account multiple (or zero) rows being inserted
PRINT
并不能阻止交易的发生,你需要THROW
。请注意,您不应在触发器中手动ROLLBACK
,抛出异常将为您完成- 使用标量函数,这对性能非常不利。 (我无法解决这个问题,因为我不知道他们在做什么)
- 如果@max_capacity 等于 到@current_capacity 那么它也会失败,我认为这不应该发生
- 使用没有长度的
varchar
是错误的,在某些情况下它默认为varchar(1)
CREATE TRIGGER check_capacity ON takes FOR INSERT
AS
DECLARE @max_capacity INT;
DECLARE @current_capacity INT;
IF (EXISTS (SELECT 1
FROM inserted i
WHERE dbo.get_max_capacity(i.course_id, i.sec_id, i.semester, i.year) <
dbo.get_current_capacity(i.course_id, i.sec_id, i.semester, i.year)
))
THROW 70000, N'The classroom is full! Choose the others', 0;
GO
如果您希望在错误消息中显示确切的数字,您可以这样做,但它只会显示第一个不合格行的结果:
CREATE TRIGGER check_capacity ON takes FOR INSERT
AS
DECLARE @max_capacity INT;
DECLARE @current_capacity INT;
SELECT TOP (1)
@max_capacity = v.max_capacity,
@current_capacity = v.current_capacity
FROM inserted i
CROSS APPLY (VALUES
(dbo.get_max_capacity(i.course_id, i.sec_id, i.semester, i.year),
dbo.get_current_capacity(i.course_id, i.sec_id, i.semester, i.year))
) v(max_capacity, current_capacity)
WHERE v.max_capacity < v.current_capacity;
IF (@@ROWCOUNT > 0)
BEGIN
DECLARE @msg nvarchar(150) = CONCAT('Max capacity ', @max_capacity, '
Current capacity ', @current_capacity, '
The classroom is full! Choose the others');
THROW 70000, @msg, 0;
END;
GO
这样做
SELECT @course_id = course_id,
@sec_id = sec,
@semester = semester,
@year_ = year
FROM INSERTED
然后设置其他值。