审核审核数据以查找缺少数据的位置以及查看时间

时间:2018-03-13 13:17:21

标签: sql

我需要查看一个不应该是ExternalRefId字符串字段为null的审计记录,然后确定在匹配UserId(非PK)int的下一条记录之前需要多长时间才填充该字段(如果有的话)。 / p>

我知道如何使用entityframework / linq2sql来做这件事,但我无法理解如何在SQL中产生这样的结果。

理想情况下,只需确定是否已超过一小时,但可能会更改为30米。

目前表格如下,

UserId | ExternalRefId   |    Action | Timestamp

xxxx  |  (xxxx-xxxx)/(null) | Insert/update/delete | xxxx-xx-xx xx:xx:xx.xxx

理想的输出,

UserId  |  NullLengthOfTime

(xxxx)    |  (xxxx-xx-xx...) / (null)

现在我正在使用多个选项进行过滤,但我觉得这种查询真的需要我之前没用过的游标。

非常感谢任何帮助/指导。

编辑: -

ExternalRefId(ERI)

应始终填充ERI,但因为它是null,因为它们会导致isses,因为这些是整个表审核,因此唯一不需要的时间是不再显示的删除。 (这是我们发送的外部记录,我们审核并且通常不发送EFI,然后打破主记录)

1 个答案:

答案 0 :(得分:1)

这就是你要追求的吗?

设置演示数据

declare @MyAuditTable table 
(
    UserId nvarchar(32) not null 
    ,ExternalRefId nvarchar(32) null
    ,Action nvarchar(32) not null
    ,Timestamp DateTime not null
)

insert @MyAuditTable (UserId, ExternalRefId, Action, Timestamp)
values ('Anne', '123','insert','2017-01-01 00:00:00')
, ('Anne', null,'update','2017-01-05 00:00:00')
, ('Anne', null,'update','2017-01-06 00:00:00') --it's already null, so don't show this again
, ('Bill', null,'insert','2017-01-07 00:00:00')
, ('Anne', '1234','update','2017-01-09 00:00:00')
, ('Claire', null,'insert','2017-02-02 00:00:00')
, ('Bill', '456','update','2017-02-24 00:00:00')
, ('Claire', null,'delete','2017-04-13 00:00:00') --though it's still null it's deleted, so fixed by removal
, ('Dave', null,'insert','2017-09-28 00:00:00') --never fixed, so doesn't show up
, ('Anne', null,'update','2017-10-14 00:00:00') --someone broke Anne again!
, ('Anne', '123','update','2017-10-15 00:00:00') --fixed

实际查询

select EntryMadeInvalid.UserId
, EntryMadeInvalid.TimeStamp IssueBegan
, EntryMadeValid.TimeStamp  IssueEnded --will show null if issue is still open 
, DATEDIFF(MINUTE, EntryMadeInvalid.TimeStamp, coalesce(EntryMadeValid.TimeStamp,getutcdate())) NullLengthOfTimeInMinutes --if issue is still open reports up to current time
from
(
    --find all entries which create or amend a value to become null
    Select *
    from @MyAuditTable a
    where ExternalRefId is null 
    and Action in ('Insert', 'Update')
    and --ignore scenarios where the null issue already existed
    (
        select top 1 case when b.ExternalRefId is null then 1 else null end
        from @MyAuditTable b
        where b.UserId = a.UserId
        and b.Timestamp < a.Timestamp
        order by b.Timestamp desc
    ) is null
) EntryMadeInvalid 
outer apply
(
    select top 1 *
    from @MyAuditTable
    where UserId = EntryMadeInvalid.UserId
    and Timestamp > EntryMadeInvalid.TimeStamp
    and (Action = 'Delete' or ExternalRefId is not null)
    order by Timestamp 
) EntryMadeValid

结果

UserId | IssueBegan              | IssueEnded              | NullLengthOfTimeInMinutes
------------------------------------------------------------------------------------
Anne   | 2017-01-05 00:00:00.000 | 2017-01-09 00:00:00.000 | 5760
Bill   | 2017-01-07 00:00:00.000 | 2017-02-24 00:00:00.000 | 69120
Claire | 2017-02-02 00:00:00.000 | 2017-04-13 00:00:00.000 | 100800
Dave   | 2017-09-28 00:00:00.000 | NULL                    | 239884
Anne   | 2017-10-14 00:00:00.000 | 2017-10-15 00:00:00.000 | 1440

解释

子查询EntryMadeInvalid

此代码的目的是查找数据首次变得不正确的条目。错误定义为ExternalRefId为空。

我也在Action in ('Insert', 'Update')上过滤,因为要成为null,大概必须插入或更新数据;这是可选的。

最后,我删除任何未使值为null的条目,而是将其保留为null。这是通过查找同一用户的直接前任并查看ExternalRefId是否为空来完成的。如果是,那么我们不关心这个记录。如果不存在,或者此用户没有先前的记录,则这是第一次因为具有值(或不存在)而使值变为空。

子查询EntryMadeValid

此查询的目的是查找给定记录从null变为具有值的位置。

我们这样做是通过选择第一条记录,然后是空记录,该记录是针对同一用户的,其中ExternalRefId不为null(或者操作是删除的;如果我们假设一旦记录被删除它的空值不再是问题)。

外部申请

基本上我们正在加入;我们只是取代完整的表然后尝试匹配记录,而是从第一组中获取每个结果并使用它来过滤第二组的数据。

我们使用的是outer而不是cross,因为即使第二个子查询没有结果,我们仍然需要第一条记录;即我们希望那些仍为空/未经过修正的值。