0

我有一个审计日志表,针对一个业务对象记录来自多个表的更改。日志带有时间戳,单个业务对象的更新很可能会在一段时间内发生。换句话说,保存一份合同最多可能需要 5 秒,而在此期间添加或更新的记录将跨越该时间。从下表中,最后一列显示时间戳,值之间略有差异。

cm_contract 1087    2013-05-20 14:30:24.713
cm_contract 1087    2013-05-20 14:30:24.717
cm_contract 1087    2013-05-20 14:30:24.750
cm_contract 1087    2013-05-20 14:30:24.763
cm_contract 1087    2013-05-20 14:30:24.817
cm_contract 1087    2013-05-20 14:30:24.833
cm_contract 1087    2013-05-20 14:30:24.837
cm_contract 1087    2013-05-20 14:30:24.843
cm_contract 1087    2013-05-20 14:30:24.850
cm_contract 1087    2013-05-20 14:30:24.853

在查看器中,我想汇总数据,显示已更改的业务对象以及针对该业务对象的日志数量。为此,我需要按业务对象和键以及具有相似时间戳的记录对记录进行分组。我已经使用临时表和变量实现了这一点,但我最终想把它放到一个视图中,所以我想知道是否有更简单的方法来做到这一点:

SELECT ROW_NUMBER() OVER (ORDER BY business_object_table, business_object_key, mod_date) AS row_num, 
        audit_trail_key, business_object_table, business_object_key, mod_date, 0 AS part
INTO #temp
FROM audit_trail WHERE business_object_table is not null

DECLARE @part INT=0

UPDATE t2 SET @part = CASE WHEN ABS(DATEDIFF(millisecond, t2.mod_date, t1.mod_date)) < 1000 THEN @part ELSE @part + 1 END, part = @part
FROM #temp t2 INNER JOIN #temp t1 ON t2.row_num = t1.row_num +1
WHERE t2.business_object_table = t1.business_object_table 
AND t2.business_object_key = t1.business_object_key

SELECT * FROM #temp 

DROP TABLE #temp

我一直在寻找 T-SQL 中的效果

CLUSTER BY ABS(DATEDIFF(millisecond, t2.mod_date, t1.mod_date)) < 1000

但不断重定向到 SQL Server 故障转移集群,这不是我想要的。有人有想法么

4

4 回答 4

1

SELECT CAST(CONVERT(datetime,mod_date) 作为浮点数)

会给你一个日期的双重表示。

然后,您可以将其除以并丢弃一些小数位以获得某种“相似的时间戳”。

但是,您似乎缺少业务逻辑的一个基本部分 - 一些对参与事务的所有行都通用的标识符。没有这个,你在猜测,任何类型的多用户活动都会导致问题。我会放弃您基于时间的方法,并在日志中传播某种事务标识符(*不是 SQL 事务 - 业务事务)。

于 2013-05-22T13:17:43.523 回答
1

我建议您将您的时间戳转换为 Smalldatetime,它可以与 minite 的 prescioson 保持时间。它取代了您的案例陈述。Count 将完成剩下的工作。

SELECT business_object_table, business_object_key, cast (mod_date as smalldatetime) as mod_date, count (*) as No_of_Changes
FROM audit_trail 
WHERE business_object_table is not null
GROUP BY business_object_table, business_object_key, cast (mod_date as smalldatetime)
ORDER BY 3,1,2

希望这可以帮助。

于 2013-05-22T14:15:24.917 回答
1

也许尝试这样的事情作为开始(“伪SQL”,未测试):

select t1.myRowId, t1.contractId, min(t2.timestamp) - t1.timestamp as DeltaT
from myTable t1
inner join myTable t2 on t1.contractId = t2.contractId and t2.timestamp > t1.timestamp
group by t1.myRowId, t1.contractId
having min(t2.timestamp) - t1.timestamp > "60 seconds"
于 2013-05-22T12:54:29.650 回答
0

我提出的解决方案类似于上面接受的答案,但通过使用两次连续更新之间的时间而不是一段时间内的所有更新来更好地支持不同的批量大小。我希望类似的解决方案也可以用于对地理空间数据进行聚类——我想有人可能会觉得这很有趣。

总而言之,我使用公用表表达式为每个审计记录生成一个行号,按业务对象类型、键和记录日期排序。

然后我使用另一个 cte 从 cte1 中提取之前更新超过一秒的每条记录,并为此结果集生成一个连续的行号。

然后我自加入 cte2 以检索每个连续记录之间所有审计记录的摘要。示例代码如下:

-- Audit record row numbers by business object table, key and mod_date
WITH cte1 AS (SELECT ROW_NUMBER() OVER (ORDER BY business_object_table, business_object_key, mod_date) AS row_num, audit_trail_key,
        business_object_table, business_object_key, mod_date, user_key, business_object_name FROM audit_trail),
-- Get audit records where previous update was more than a second prior, and include the first audit record
cte2 AS (SELECT ROW_NUMBER() OVER (ORDER BY a2.row_num) AS row_num, a2.audit_trail_key,
        a2.business_object_table, a2.business_object_key, a2.mod_date, a2.user_key, a2.business_object_name
    FROM cte1 a2 LEFT JOIN cte1 a1 ON a2.row_num = a1.row_num + 1 AND a2.business_object_table = a1.business_object_table
        AND a2.business_object_key = a1.business_object_key
    WHERE ABS(DATEDIFF(ss, a1.mod_date, a2.mod_date)) > 1 OR a1.audit_trail_key IS NULL
    AND a2.business_object_table is not null)
-- Summarise details within each cluster    
SELECT a1.audit_trail_key, a1.business_object_table, a1.business_object_key, a1.mod_date AS first_mod, 
    u.username, a1.user_key, a1.business_object_name, 
    (SELECT audit_rec_table + ': ' + CAST(COUNT(*) AS VARCHAR) + ' record' +
        CASE WHEN COUNT(*) > 1 THEN 's' ELSE '' END + CASE mod_type WHEN 'U' THEN ' Changed' WHEN 'D' 
                THEN ' Deleted' ELSE ' Added' END + CHAR(10) FROM audit_trail
        WHERE business_object_table = a1.business_object_table AND business_object_key = a1.business_object_key 
                AND mod_date >= a1.mod_date AND mod_date < ISNULL(a2.mod_date, mod_date + 1)
        GROUP BY audit_rec_table, mod_type
        FOR XML PATH('')) AS change_summary
FROM cte2 a1 LEFT JOIN cte2 a2 ON a2.row_num = a1.row_num + 1 AND a2.business_object_table = a1.business_object_table
        AND a2.business_object_key = a1.business_object_key
    INNER JOIN su_user u ON u.user_key = a1.user_key
于 2013-05-30T13:28:25.247 回答