【问题标题】:How to update a sql table column on every certain minutes interval?如何每隔一定的分钟间隔更新一个 sql 表列?
【发布时间】:2017-03-03 17:38:11
【问题描述】:

在 SQL 表中,我将列作为 Start_Date、End_Date 和 IsActive。

在每次插入时,Start_Date 都有一个有效的日期时间条目,End_Date 为 Null,IsActive 为 0。

30 分钟后,我需要将 End_Date 更新为当前日期时间,并将 IsActive 更新为 1。这是在 SQL Express 中。我不能使用作业调度程序。我不喜欢使用 Windows 任务计划程序。

触发器有插入或更新后的限制。有办法处理吗?

【问题讨论】:

  • 为什么不能使用调度器?您在这里有两个选择....要么只是在插入期间设置值,要么使用计划任务。可悲的是,这有点奇怪。为什么你只是盲目地在 30 分钟内更新 End_Date?这是没有意义的。它只是假设它必须有效。这比将来创建行时将值设置为 30 有什么好处?
  • 您可以使用 Service Broker 队列激活的存储过程以及会话计时器 (msdn.microsoft.com/en-us/library/ms187804.aspx)。
  • 该行记录使用 30 分钟的逻辑.. 30 分钟后,该行记录将处于非活动状态。所以我需要设置 end_date 时间戳
  • 那么为什么不直接设置插入行的日期呢?这将比以后更新更容易、更准确。
  • 为什么同时需要 InactiveDate 和 IsActive? InactiveDate 早于它不再处于活动状态的当前日期还不够吗?不过我有点困惑,您声明您希望 IsActive 变为 1。我的猜测是这是一个位列,通常 1 表示真,但在这种情况下 IsActive 会是假的,对吧?所以它应该变成0,或者正如我已经说过的,这个专栏似乎是多余的。

标签: sql-server sql-server-express


【解决方案1】:

下面的示例使用服务代理激活的存储过程和会话计时器定期更新表。收到 DialTimer 消息后,激活的 dbo.UpdateSqlTableOnTimer proc 更新表并启动一个新计时器。 dbo.StartUpdateSqlTableOnTimer proc 启动初始计时器并返回对话句柄。如果需要,指定 dbo.StopUpdateSqlTableOnTimer 的句柄以停止计时器循环。

请注意,数据库必须启用服务代理。如果尚未启用,请使用ALTER DATABASE 启用服务代理:

ALTER DATABASE YourDatabase
    SET ENABLE_BROKER;

USE YourDatabase;
GO

CREATE PROC dbo.StartUpdateSqlTableOnTimer
--begin initial conversation and timer
AS
DECLARE @ConversationHandle uniqueidentifier;
BEGIN DIALOG CONVERSATION @ConversationHandle
    FROM SERVICE UpdateSqlTableOnTimer
    TO SERVICE 'UpdateSqlTableOnTimer', 'CURRENT DATABASE'
    ON CONTRACT [DEFAULT]
    WITH ENCRYPTION = OFF;
BEGIN CONVERSATION TIMER (@ConversationHandle)  
    TIMEOUT = 1800;
SELECT @ConversationHandle AS ConversationHandle;
GO

CREATE PROC dbo.StopUpdateSqlTableOnTimer
    @ConversationHandle uniqueidentifier
--end conversation
AS
END CONVERSATION @ConversationHandle;
GO

CREATE PROC dbo.UpdateSqlTableOnTimer
AS

SET XACT_ABORT ON;
SET NOCOUNT ON;

DECLARE
      @ConversationHandle uniqueidentifier
    , @MessageTypeName sysname
    , @EventNotificationDetails xml
    , @EventLogMessage nvarchar(MAX);

BEGIN TRY

    BEGIN TRAN;

    RECEIVE TOP(1)
            @ConversationHandle = conversation_handle
        , @MessageTypeName = message_type_name
        , @EventNotificationDetails = CAST(message_body AS xml)
    FROM dbo.QueueForUpdateSqlTableOnTimer;

    IF @@ROWCOUNT > 0
    BEGIN

        IF @MessageTypeName = N'http://schemas.microsoft.com/SQL/ServiceBroker/DialogTimer'
        BEGIN

            --update IsActive and End_Date here

            --start new timer
            BEGIN CONVERSATION TIMER (@ConversationHandle)  
                TIMEOUT = 1800; 
        END
        ELSE
        BEGIN
            IF @MessageTypeName = N'http://schemas.microsoft.com/SQL/ServiceBroker/EndDialog'
            BEGIN
                END CONVERSATION @ConversationHandle;
            END
            ELSE
            BEGIN
                END CONVERSATION @ConversationHandle WITH ERROR = 1 DESCRIPTION = 'Unexpected message type received';
            END;
        END;

    END;

    COMMIT;

END TRY
BEGIN CATCH

    IF @@TRANCOUNT > 0 ROLLBACK;
    THROW;

END CATCH;
GO

--create queue with proc activation
CREATE QUEUE dbo.QueueForUpdateSqlTableOnTimer
    WITH STATUS=ON,
    ACTIVATION (
        PROCEDURE_NAME = dbo.UpdateSqlTableOnTimer,
        MAX_QUEUE_READERS = 1,
        EXECUTE AS OWNER ) ;
GO

CREATE SERVICE UpdateSqlTableOnTimer
    ON QUEUE dbo.QueueForUpdateSqlTableOnTimer
    ([DEFAULT]);
GO

EXEC dbo.StartUpdateSqlTableOnTimer;
GO

EXEC dbo.StopUpdateSqlTableOnTimer @ConversationHandle = '<specify value from dbo.StartUpdateSqlTableOnTimer>';
GO

【讨论】:

  • 非常感谢您分享一个示例..虽然我们的逻辑已经改变..我非常感谢分享服务代理和对话计时器示例..
猜你喜欢
  • 2017-10-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多