使用触发器基于两个非DateTime值更新DateTime值

时间:2014-10-07 14:00:32

标签: sql sql-server datetime triggers data-conversion

一些背景知识:

我目前正在使用SQL Server数据库驱动的应用程序,该应用程序包含审计表,这些表根据用户执行的某些操作自动更新。我们有一个功能请求,以DateTime的形式向这些审计表添加其他信息。问题在于,所需日期时间对象的源数据仅存在于两个字符串值(一个用于日期,一个用于时间),这些值存储在“对象属性”表中(我们无法修改,因为它形成键值对形式的软件堆栈的核心部分。包含信息的“属性表”看起来有点像这样:

| Foreign_Key (uniqueidentifier) |  Data_Key (nvarchar) | Data_Value (nvarchar) |
|             {guid 1}           |        'Date'        |       '10/11/12'      |
|             {guid 1}           |        'Time'        |         '1315'        |
|             {guid 2}           |        'Date'        |       '11/12/13'      |
|             {guid 2}           |        'Time'        |         '1416'        |

我们要尝试实现的是根据上述数据将纯DateTime值插入审计表(出于此问题的目的,我们可以修改)。理想的输出是:

| Primary_Key (uniqueidentifier) |     DateT_Value (datetime)   |
|            {guid 1}            |       10/11/12 13:15:00      | 
|            {guid 2}            |       11/12/13 14:16:00      | 

为了强制执行此操作,我为源表编写了以下SQL Server触发器,根据相关对象的ID,该表应根据存储在属性表中的两个字符串值创建DateTime值。 :

DECLARE @DateFormat INT
SET @DateFormat = -- Subquery to retrieve date format ID - removed for clarity

UPDATE AuditTable
SET DateT_Value = 
    DATEADD (minute,
            (CONVERT(INT, SUBSTRING(
                    (SELECT Data_Value  
                     FROM inserted
                     WHERE inserted.Data_Key = 'Time'
                     AND inserted.Foreign_Key = AuditTable.Primary_Key)
                     , 3, 2)) + ((CONVERT(INT, SUBSTRING(
                                    (SELECT Data_Value  
                                     FROM inserted
                                     WHERE inserted.Data_Key = 'Time'
                                     AND inserted.Foreign_Key = AuditTable.Primary_Key),
                                1, 2))) * 60)),
             CONVERT(DATETIME, 
                        (SELECT Data_Value
                         FROM inserted
                         WHERE inserted.Data_Key = 'Date'
                         AND inserted.Foreign_Key = AuditTable.Primary_Key),
                     @DateFormat))
FROM AuditTable
INNER JOIN inserted
ON inserted.Foreign_Key = AuditTable.Primary_Key

现在,当我尝试独立运行此查询时(删除对'inserted'的引用并将内存表替换为它将引用的实际表的实例),它工作正常 - DateT_Value字段将按预期为审计表中的所有行填充。

然而,当这个逻辑放在一个触发器中并且我试图使用'inserted'表(理论上它应该包含所有被添加到'source'表中的行)时,我得到一个NULL值被插入'audit'表的DateTime字段。

我只能假设无论出于何种原因,'inserted'表都不会将任何行返回到外部更新语句 - 但是假设我基于ID(已知是唯一的)和字段名称加入转换逻辑中的源表(在这种情况下,它永远不会包含特定字段的多个数据实例)我会认为这样就足够了吗?

值得注意的是,我尝试从触发器中删除复杂的日期转换逻辑并将其替换为简单的

UPDATE AuditTable
SET DateValue = GETDATE() -- Fake date
FROM AuditTable
INNER JOIN inserted
ON inserted.Foreign_Key = AuditTable.Primary_Key

用于调试目的 - 但我仍然看到相同的行为。

我遗漏了'inserted'表的行为吗?

干杯。

1 个答案:

答案 0 :(得分:0)

关于时间安排。当您使用触发器时,它尚未反映到db。在该事务中,您尝试获取值并尝试加入,但尚未在触发器中创建该值。拆分查询,首先插入,然后更新