我需要首先检查我的表中的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,
)
答案 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
含义会有所不同,但前者中的行号将指向触发的位置声明,而后者中的行号将引用触发器中的位置。