在SQL中插入另一个记录之前,检查列是否为null

时间:2014-07-11 09:44:42

标签: sql-server-2008 stored-procedures

我需要首先检查我的表中的EndTime列是否为null,然后才能插入另一条记录。如果Endtime列不为空,则可以插入新记录,否则必须抛出错误。我不确定如何在SQL中创建错误。

这是我尝试的但它不起作用

ALTER PROCEDURE [dbo].[AddDowntimeEventStartByDepartmentID]
   (@DepartmentId int,
    @CategoryId int,
    @StartTime datetime,
    @Comment varchar(100) = NULL)
AS
BEGIN TRY
   PRINT N'Starting execution'

   SET @StartTime = COALESCE(@StartTime, CURRENT_TIMESTAMP);

   INSERT INTO DowntimeEvent(DepartmentId, CategoryId, StartTime, EndTime, Comment)
   WHERE EndTime = NULL
   OUTPUT
       inserted.EventId, inserted.DepartmentId, 
       inserted.CategoryId, inserted.StartTime,
       inserted.EndTime, inserted.Comment   
   VALUES(@DepartmentId, @CategoryId, @StartTime, NULL, @Comment)
END TRY
BEGIN CATCH
    SELECT ERROR_NUMBER(),ERROR_MESSAGE()
END CATCH

这是我的表:

CREATE TABLE [dbo].[DowntimeEvent](
    [EventId] [int] IDENTITY(0,1) NOT NULL,
    [DepartmentId] [int] NOT NULL,
    [CategoryId] [int] NOT NULL,
    [StartTime] [datetime] NOT NULL,
    [EndTime] [datetime] NULL,
    [Comment] [varchar](100) NULL,
)

2 个答案:

答案 0 :(得分:0)

您可以使用INSERT...SELECT语法而不是INSERT...VALUES来使用WHERE子句(与您尝试使用的条件具有不同的条件,请参阅下文),然后检查{{ 3}}和number of affected rows如果是0:

...

BEGIN TRY
    ...

    INSERT INTO DowntimeEvent
      ...
    SELECT @DepartmentId, @CategoryId, @StartTime, NULL, @Comment
    WHERE NOT EXISTS (
      SELECT *
      FROM dbo.DowntimeEvent
      WHERE DepartmentId = @DepartmentId
        AND CategoryId = @CategoryId
        AND EndTime IS NULL
    );

    IF @@ROWCOUNT = 0
      RAISERROR ('A NULL row already exists!', 16, 1)
    ;
END TRY
BEGIN CATCH
    ...
END CATCH;

(当然,您需要将您的 WHERE子句省略为无效的Transact-SQL。)

答案 1 :(得分:0)

如果您想在数据库级别而不是仅在存储过程中使用预防机制,以便能够防止来自任何调用者的无效添加,您可能需要考虑触发器。

这样的FOR INSERT触发器会检查新行是否违反规则“不添加比现有NULL行更新的行”(以及“不要添加空行EndTime的旧行” )如果他们这样做,则回滚交易:

CREATE TRIGGER DowntimeEvent_CheckNew
ON dbo.DowntimeEvent
FOR INSERT, UPDATE

-- do nothing if EndTime is not affected
IF NOT UPDATE(EndTime)
  RETURN
;

-- raise an error if there is an inserted NULL row
-- older than another existing or inserted row
IF EXISTS (
  SELECT *
  FROM dbo.DowntimeEvent AS t
  WHERE t.EndTime IS NULL
    AND EXISTS (
      SELECT *
      FROM inserted AS i
      WHERE i.DepartmentId = t.DepartmentId
        AND i.CategoryId   = t.CategoryId
        AND i.StartTime   >= t.StartTime
    )
)
BEGIN
  RAISERROR ("An attempt to insert an older NULL row!", 16, 1);
  ROLLBACK TRANSACTION;
END;

-- raise an error if there is an inserted row newer
-- than the existing NULL row or an inserted NULL row
IF EXISTS (
  SELECT *
  FROM inserted AS i
  WHERE i.EndTime IS NULL
    AND EXISTS (
      SELECT *
      FROM dbo.DowntimeEvent AS t
      WHERE t.DepartmentId = i.DepartmentId
        AND t.CategoryId   = i.CategoryId
        AND t.StartTime   >= i.StartTime
    )
)
BEGIN
  RAISERROR ("An older NULL row exists!", 16, 1);
  ROLLBACK TRANSACTION;
END;

请注意,仅在触发器中发出ROLLBACK TRANSACTION意味着会引发16级错误,如下所示:

Msg 3609, Level 16, State 1, Line nnn
The transaction ended in the trigger. The batch has been aborted.

所以,你可能不需要自己的。上面的消息与您自己的Line nnn带来的消息之间的RAISERROR含义会有所不同,但前者中的行号将指向触发的位置声明,而后者中的行号将引用触发器中的位置