【问题标题】:MSSQL Trigger Update on column列上的 MSSQL 触发器更新
【发布时间】:2019-03-13 09:30:53
【问题描述】:

我有 2 个表,我希望表 1 有一个在表 2 中插入或更新的触发器,但我不知道该怎么做。

表一:

CREATE TABLE [dbo].[DevicePorts](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [IsInUse] [bit] NOT NULL,
)

表2:

CREATE TABLE [dbo].[DevicePortActivities](
    [ID] [uniqueidentifier] NOT NULL,
    [StartTime] [datetimeoffset](7) NOT NULL,
    [EndTime] [datetimeoffset](7) NULL,
    [FK_DevicePortID] [int] NOT NULL FOREIGN KEY REFERENCES DevicePorts(ID),
)

我的触发器开始:

CREATE TRIGGER PortInUse
   ON  DevicePorts
   AFTER UPDATE
AS BEGIN
    SET NOCOUNT ON;
    IF UPDATE (IsInUse) 
    BEGIN
        IF IsInUse = 1
        THEN
            INSERT INTO [dbo].[DevicePortActivities]
            (
                [ID]
                ,[StartTime]
                ,[EndTime]
                ,[FK_DevicePortID]
            )
            VALUES
            (
                NEWID(),
                SYSDATETIMEOFFSET(),
                null,
                <DevicePortID>
            )
        ELSE 
            UPDATE [dbo].[DevicePortActivities]
            SET EndTime = SYSDATETIMEOFFSET()
            WHERE FK_DevicePortID = <DevicePortID> AND EndTime is null
        END
    END 
END
GO

我想要做的是,当“IsInUse”被修改时,它应该在“DevicePortActivities”中插入一行或更新。

条件是,如果“IsInUse”为真,则应插入一条记录,如果为假,则应更新“EndTime”为空的最后一条记录。

【问题讨论】:

标签: sql-server triggers sql-update


【解决方案1】:

您需要将inserted 视为一个表格。我建议为此查看MERGE(因为单个UPDATE 可能对不同的行进行了不同的更改)。

类似:

CREATE TRIGGER PortInUse
   ON  DevicePorts
   AFTER UPDATE
AS
BEGIN
    SET NOCOUNT ON;
    MERGE INTO [dbo].[DevicePortActivities] t
    USING (select i.ID,i.IsInUse as NewUse,d.IsInUse as OldUse
        from inserted i inner join deleted d on i.ID = d.ID) s
    ON
        t.FK_DevicePortID = s.ID
    WHEN MATCHED AND t.EndTime is null AND NewUse = 0 and OldUse = 1
    THEN UPDATE SET EndTime = SYSDATETIMEOFFSET()
    WHEN NOT MATCHED AND NewUse = 1 and OldUse = 0
    THEN INSERT ([ID]
                ,[StartTime]
                ,[EndTime]
                ,[FK_DevicePortID])
         VALUES (NEWID(),
                SYSDATETIMEOFFSET(),
                null,
                s.ID);
END

【讨论】:

  • 非常感谢,从未听说过“合并”——但我一定会调查的。
【解决方案2】:

我为我的问题找到了解决方案

CREATE TRIGGER [dbo].[PortInUse]
   ON  [dbo].[DevicePorts]
   AFTER UPDATE
AS BEGIN
    SET NOCOUNT ON;
    IF UPDATE (IsInUse) 
    BEGIN
        DECLARE @IsInUse bit;
        DECLARE @PortID int;
        SELECT @IsInUse = i.IsInUse FROM inserted i; 
        SELECT @PortID = i.ID FROM inserted i; 
        IF (@IsInUse = 1)
            INSERT INTO [dbo].[DevicePortActivities]
            (
                [ID]
                ,[StartTime]
                ,[EndTime]
                ,[FK_DevicePortID]
            )
            VALUES
            (
                NEWID(),
                SYSDATETIMEOFFSET(),
                null,
                @PortID
            );
        ELSE 
            UPDATE [dbo].[DevicePortActivities]
            SET EndTime = SYSDATETIMEOFFSET()
            WHERE FK_DevicePortID = @PortID AND EndTime is null;
    END 
END

我不确定是否有更好的方法来做到这一点,但它正在工作。

【讨论】:

  • ""working",但不是真的。inserted 可以包含 0、1 或 许多 行(取决于受影响的行数通过更新)。您可以从这些数据组合中任意获取值并将它们放入标量变量中。您甚至无法保证您从同一行中获得一致的 IsInUseID。您需要编写将inserted 正确视为表格的代码。我建议您查看MERGE
猜你喜欢
  • 2021-03-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-14
  • 2019-12-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多