【问题标题】:Update inserted record on a trigger更新触发器上的插入记录
【发布时间】:2015-05-14 11:36:58
【问题描述】:

当通过外部应用程序将记录插入数据库时​​尝试更新记录时遇到问题。

我需要从应用程序中的用户插入的记录从表 AERO_LOCATIONSTOCKMIN 中获取值 MinimumStock,该表是父位置和资产类型

LOCATIONSTOCKMINID  ASSETTYPEID   LOCATIONID    MINIMUMSTOCK
   54000000001      54000000043   43200000357      12.00
   54000000002      54000000043   43200000883      6.00

这是目的:当用户尝试在Asset 表上插入记录(通过外部应用程序)时,触发器必须检查用户是否为该Asset 选择了位置。如果是这样,触发器必须检索所选位置的父位置,并检查是否为此 AssetType 和此父位置定义了最低库存。

如果全部满足,触发器必须将字段UDFText01设置为上表中定义的最小库存。

这是我迄今为止尝试过的。触发器很好地检查了需求,但在尝试 UPDATE 并引发以下错误时失败:

The transaction ended in the trigger. The batch has been aborted.

我尝试以多种方式修改 UPDATE 语句,但它们都引发了相同的错误消息。

编辑

按照@Sean Lannge 的建议,我编辑了触发器以管理多个插入。触发器不再显示错误消息,但更改(插入)未保存到数据库中。

ALTER TRIGGER [spectwosuite].[TRI_ASSET_STOCKMIN] ON [spectwosuite].[ASSET]
FOR INSERT AS 
BEGIN
  IF (UPPER(USER) != 'SPECTWOREPLENG')

    DECLARE @assettypeid numeric(15);
    DECLARE @assetid numeric(15);
    DECLARE @locationid numeric(15);
    DECLARE @parentlocationid numeric(15);
    DECLARE @stockmin numeric(9,2);
    DECLARE @mistock varchar(100);


    DECLARE crs_ROWS CURSOR FOR
    SELECT ASSETID, ASSETTYPEID, LOCATIONID
    FROM inserted;

    OPEN crs_ROWS;
      FETCH NEXT FROM crs_ROWS INTO @assetid, @assettypeid, @locationid 
      WHILE (@@FETCH_STATUS = 0)
      BEGIN

            SELECT @parentlocationID = ParentLocationID FROM Location 
                    LEFT JOIN Asset ON Asset.LocationID = Location.LocationID
                    WHERE Asset.LocationID = @locationid;                   


            IF NOT EXISTS 
                (SELECT * FROM Location LEFT JOIN INSERTED AS i ON Location.LocationID = i.LocationID 
                    WHERE Location.LocationID = i.LocationID)
                BEGIN

                    RAISERROR ('Please fill the Location for the Asset.',16,1);
                    ROLLBACK;
                END
            ELSE            

                    IF EXISTS (SELECT MinimumStock FROM AERO_LOCATIONSTOCKMIN
                        WHERE AssetTypeID = @assettypeid AND LocationID = (SELECT ParentLocationID FROM Location WHERE LocationID = @locationID))

                        BEGIN

                            SELECT @stockmin = MinimumStock FROM AERO_LOCATIONSTOCKMIN
                                WHERE AssetTypeID = @assetTypeID AND LocationID = 
                                        (SELECT ParentLocationID FROM Location WHERE LocationID = @locationID);

                                SELECT @mistock= CONVERT(varchar(100),@stockmin);   
                                --RAISERROR (@mistock,16,1);            


                                UPDATE spectwosuite.ASSET
                                SET UDFText01 = @mistock 
                                FROM
                                     INSERTED I
                                INNER JOIN spectwosuite.ASSET T ON
                                     T.AssetID = I.AssetID

                            --UPDATE spectwosuite.ASSET SET UDFText01 = @mistock
                            --  FROM spectwosuite.ASSET AS A INNER JOIN inserted AS I
                            --  ON A.AssetID = I.AssetID;                   

                        END

                    ELSE
                            RAISERROR ('The parent Location for the Asset Type doesn't have minimum stock defined',16,1);
                            ROLLBACK;

       FETCH NEXT FROM crs_ROWS INTO @assetid, @assettypeid, @locationid; 
      END;
      CLOSE crs_ROWS;
      DEALLOCATE crs_ROWS;

END;

【问题讨论】:

  • UDFText01 字段是否是用户输入数据的表的列之一(使用外部应用程序?)
  • @S.Krishna 是的。
  • 我认为在这种情况下您将需要使用“代替”触发器。看到这个 SO stackoverflow.com/questions/5341584/…
  • 但我想让外部应用程序执行自己的INSERT 语句,然后添加我自己的UPDATE 语句以将值设置为UDFText01。这可能吗?
  • 我认为这不是一个好主意。当您使用“而不是”触发器时,插入仍在您的外部应用程序中进行,只是您正在根据您提到的场景添加更多输入。

标签: sql-server triggers insert sql-update


【解决方案1】:

根据此处的扩展讨论,看看这样的事情是否更接近你想要做的事情。

ALTER TRIGGER [spectwosuite].[TRI_ASSET_STOCKMIN] ON [spectwosuite].[ASSET] FOR INSERT AS 
IF (UPPER(USER) != 'SPECTWOREPLENG')
BEGIN

    create table #MyInsertedCopy
    (
        --whatever columns go here that you want to display for error rows
        ErrorMessage varchar(50)
    )

    insert #MyInsertedCopy
    select i.* --use your real columns, not *
        , 'Please fill the Location for the Asset' as ErrorMessage
    from inserted i
    left join Location l on l.LocationID = i.LocationID 
    where l.LocationID IS NULL

    insert #MyInsertedCopy
    select i.* --use your real columns, not *
        , 'The parent location for that Asset doesn''t have minimum stock defined' as ErrorMessage
    from inserted i
    left join AERO_LOCATIONSTOCKMIN a on a.AssetTypeID = i.AssetID
    left join Location l on l.ParentLocationID = i.LocationID 
    where a.AssetTypeID is NULL

    update a
    set UDFText01 = MinimumStock 
    FROM INSERTED I
    INNER JOIN spectwosuite.ASSET T ON T.AssetID = I.AssetID
    INNER JOIN AERO_LOCATIONSTOCKMIN a on a.AssetTypeID = i.AssetID
    INNER JOIN Location l on l.ParentLocationID = i.LocationID 

    IF EXISTS(select * from #MyInsertedCopy) 
        --do something to report that there are rows that failed
        select * from #MyInsertedCopy
END

【讨论】:

  • 非常感谢@SeanLange。由于我目前不在办公室,因此我将尽快尝试您的解决方案并使用我的 cmets 恢复。再次感谢您的时间和奉献精神!
  • 在对表字段相关性进行一些修改后(例如:a.AssetTypeID = i.AssetID > a.AssetTypeID = i.AssetTypeID),您的解决方案运行良好。再次感谢!
猜你喜欢
  • 2013-06-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-06
  • 1970-01-01
  • 2012-03-06
  • 1970-01-01
相关资源
最近更新 更多