我需要查看一个不应该是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,然后打破主记录)
答案 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
,因为即使第二个子查询没有结果,我们仍然需要第一条记录;即我们希望那些仍为空/未经过修正的值。