SQL Server触发器-这是否可能且正确使用

时间:2018-08-13 14:48:50

标签: sql sql-server triggers

我看了一下,但是找不到足够具体的答案来回答我的问题

首先,这可能吗?

其次,我的搜索是否还没有完成,而且已经得到了答案-如果可以,在哪里?

最后,还有一条更好的替代路线吗?

好,所以我的情况是 使用SQL Server,我有一个按计划运行的SQL作业-我想删除此计划,并说“完成此作业后,再次运行”,但我不想做最后一步=转到步骤1,而是想做类似的事情。 ..

创建一个包含PK和其他列的表以帮助控制。可以说

CREATE TABLE dbo.MyTable 
(Col1_ID INT Primary Key
, Col2_Desc VARCHAR(256),
 Col3_DT SmallDatetime default getutcdate()
,Col4_Duration INT default 60)

,然后向该表添加触发器,以便在该表上完成INSERT时运行触发器,并且如果触发器是insert,且描述为(Col2_Desc)“运行”或类似内容然后我们执行作业“ MSSQL作业名称”

如果随后我们将“ STOP”添加为Col2_Desc,则触发器将在Col4_Duration作业状态下运行几分钟而不运行MSSQLJOB。

IE

 INSERT INTO dbo.MyTable ('RUN',GETUTCDATE(),0)

触发器运行并执行MSSQLJOB XYZ

INSERT INTO dbo.MyTable ('STOP',GETUTCDATE(),60)

触发器运行并等待几分钟的持续时间

〜60分钟后,触发器运行并再次执行MSSQL作业。

这把我带到了为什么,我的工作按上述时间表进行;这项工作不会花费很长时间,也不是很重要(我们的主数据仓库:D-我是BI开发人员..),但是当它构建完成后,我想一次又一次地通过设计来构建它,虽然很快,但是我还希望能够“排定的停机时间”而不必去禁用工作本身,或者确保一切都在工作表上正常进行。我希望作业在完成当前的构建运行后,在当前运行完成一段时间后基本上停止运行-构建的最后一步将通过触发器插入表中

所以目标是,插入一行以说“ STOP for 20 minutes”,现在我可以对其进行更改,然后忘记它,因为该作业将再次运行,而MSSQL作业将再次开始连续运行。

我目前还没有一个完全正确的测试环境,我总是对定义有所更改,因为我在实际运行时就对其进行了更改-理想情况下,我想自动暂停构建一段时间将行插入表中是否可行?

理论上,我确实相信这是可能的。但是就MSSQL持续集成,简化的部署等而言-我不知道这是一个好主意还是可行的主意。

并感谢您的帮助。

谢谢, 理查德。

PS-表PK的原因,因此我可以将其添加到MVC应用程序中,然后单击以将通信发送给即将部署的利益相关者,详细信息,插入停止持续时间所需的行,然后执行部署而无需做很多事情-如果我可以创建某种形式的触发器,则可以将其自动化。

3 个答案:

答案 0 :(得分:2)

这当然是一种创造性的方法,但是我不知道有什么方法可以告诉SQL Server“从现在开始等待X分钟,然后再执行Y”。

如果我是您,我会研究一种方法,该方法包括安排作业每分钟运行一次(或您想要的精度水平),然后使用元表告诉作业是否可以做某件事或不是。

答案 1 :(得分:1)

好吧,所以我做了一些测试,没有时间去研究,但是我设法完成了我想要的工作-尽管它不是理想的并且个人感觉它不应该使用,但是只是这样任何人都可以找到并使用。

它需要您具有两个作业和两个表来控制它们。主作业和主作业调用的替代作业。然后是带有触发器的主表,以及控制要插入内容的表

我更喜欢所有其他答案,因为我的Q的开始部分是有更好的方法来做到这一点,是的。但是虽然进行测试很有趣!

这个想法是第二个控制插入内容的表,它仅将最新行作为要执行的操作“ TOP 1 ORDER BY DATE DESC”,因此该表可能会肿,但仍然可以正常工作模型-您需要烫发才能创建2个表和2个作业以及要测试的触发器。下面的代码

CREATE TABLE dbo.MyTestTable
    (
        My_PK INT Primary Key IDENTITY(1,1)
        ,My_Action VARCHAR(256)
        ,My_DateTime SMALLDATETIME
        ,My_Duration_To_Wait INT
    )

GO

    CREATE OR ALTER TRIGGER RunMyJob  
ON dbo.MyTestTable 
AFTER INSERT   
AS  
IF EXISTS(SELECT * FROM INSERTED WHERE My_Action = 'RUN')
BEGIN
    EXEC msdb.dbo.sp_start_job 'TESTJOB'
END

DECLARE @MyInt INT = (SELECT top 1 My_Duration_To_Wait FROM dbo.MyTestTableAction ORDER BY My_DateTime DESC)
DECLARE @WaitTime VARCHAR(256) = DATEADD(Minute,@MyInt,GETUTCDATE())
DECLARE @MyDelay VARCHAR(8) =  CONVERT(TIME, @WaitTime-GETUTCDATE())


IF EXISTS(SELECT * FROM INSERTED WHERE My_Action = 'STOP')
BEGIN
    PRINT 'WAITING FOR ' + CAST(@WaitTime AS VARCHAR(30)) + ' '
    WAITFOR DELAY @MyDelay
    PRINT 'Running again ' + CAST(GETUTCDATE() AS VARCHAR(256))
    EXEC msdb.dbo.sp_start_job 'TESTJOB'
END
GO   


JOB_NAME = 'TESTJOB'
JOB STEP 1 = SELECT 1
JOB STEP 2 = EXEC msdb.dbo.sp_start_job 'TESTJOBINSERT'

JOB_NAME = 'TESTJOBINSERT'
JOB STEP 1 = 
INSERT INTO dbo.MyTestTable
SELECT TOP 1 My_Action, GETUTCDATE(), My_Duration_To_Wait FROM dbo.MyTestTableAction ORDER BY My_DateTime DESC


CREATE TABLE dbo.MyTestTableAction
    (
        My_Action VARCHAR(256)
        ,My_Duration_To_Wait INT
        ,My_DateTime DATETIME
    )
INSERT INTO dbo.MyTestTableAction VALUES ('RUN',0,GETUTCDATE()) -- just run as normal


INSERT INTO dbo.MyTestTableAction VALUES ('STOP',10,GETUTCDATE()) -- Wait 10 minutes before starting again

答案 2 :(得分:0)

我会推荐这样的东西:

  1. 将作业设置为每30分钟(或您希望的任何时间)运行
  2. 向检查表的工作添加新的第一步;如果表中的最新记录显示为RUN,则继续该作业,否则退出该作业
  3. 在工作结束时添加一个步骤,在完成STOP之后,将带有RUN的新行添加到表中

新的第一步可能是这样的:

DECLARE @isRun varchar(4) = (SELECT TOP 1 Col2_Desc 
                             FROM yourTable 
                             ORDER BY Col1_ID DESC)

IF @isRun = 'RUN'
BEGIN
SELECT 'Good'
ELSE RAISERROR ('Not time to run', 16, 1)

将此步骤设置为在失败时完成作业报告成功。成功后,继续执行步骤2。

新的最后一步将是简单的插入:

INSERT INTO yourTable (Col2_Desc, timestamp) --whatever else
SELECT 'STOP', GETDATE()

这样,您需要做的就是在要运行作业时使用RUN向表中插入一行。您还可以通过查看STOP行来记录作业实际完成的时间。