(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

然后设置其他值。