首页 > 解决方案 > (SQL Server 触发器)无法绑定多部分标识符

问题描述

我尝试在 TAKES 表上创建触发器,但收到 4 个类似错误:

无法绑定多部分标识符“Inserted.course_id”。

无法绑定多部分标识符“Inserted.sec”。

无法绑定多部分标识符“Inserted.semester”。

无法绑定多部分标识符“Inserted.year”。

这是我的代码:

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

标签: sqlsql-servertsqltriggers

解决方案


此触发器有许多主要缺陷:

  • 不考虑插入多个(或零个)行
  • 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

推荐阅读