SQL查找不完整的记录集

时间:2019-03-11 17:43:13

标签: sql sql-server sql-server-2008

“不可能”是有效答案...

给出一个字段表(不是真实的字段名):

DateTime, Message, User

给出查询(返回所有集合):

SELECT * FROM tbl WHERE User = 'mfamoso' ORDER BY [DateTime] DESC

给出一组数据(3条预期记录):

+-------------------------+------------------------------------------------------------------------------------------+---------+
|        DateTime         |                                         Message                                          |  User   |
+-------------------------+------------------------------------------------------------------------------------------+---------+
| 2019-03-11 12:55:00.097 | {"V":"1.0.0","In":"Program.Main()","E":"","D":"Exporting...."}                           | mfamoso |
| 2019-03-11 12:55:00.270 | {"V":"1.0.0","In":"Program.Main()","E":"","D":"PreExportImprintHeader ran successfully"} | mfamoso |
| 2019-03-11 12:55:08.543 | {"V":"1.0.0","In":"Program.Main()","E":"","D":"CleanUp ran successfully"}                | mfamoso |
+-------------------------+------------------------------------------------------------------------------------------+---------+

问题:例如,如果缺少部分集合(缺少记录“ CleanUp ran成功运行”),是否可以获取以下查询结果:

如果主查询成功运行,则我可以有多个集合,因为主查询每10分钟作为一项服务运行一次。所有集合应具有3条记录。我需要一个查询,如果没有运行,它将返回缺少所有3条记录的集合。

+-------------------------+------------------------------------------------------------------------------------------+---------+
|        DateTime         |                                         Message                                          |  User   |
+-------------------------+------------------------------------------------------------------------------------------+---------+
| 2019-03-11 12:55:00.097 | {"V":"1.0.0","In":"Program.Main()","E":"","D":"Exporting...."}                           | mfamoso |
| 2019-03-11 12:55:00.270 | {"V":"1.0.0","In":"Program.Main()","E":"","D":"PreExportImprintHeader ran successfully"} | mfamoso |
+-------------------------+------------------------------------------------------------------------------------------+---------+

我猜测查询将使用一个计数来确保3条记录,如果没有3条记录,则显示它们-但是如何确定它们是集合的一部分?创建记录的过程大约需要10秒钟才能运行,并且每10分钟运行一次。这可能需要一个存储过程。

DateTime发生变化,Message不变。

3 个答案:

答案 0 :(得分:0)

每套仅10毫秒?

然后对于1个用户集,应将3个用户的时间四舍五入至最接近的分钟。

此查询使用该想法。

SELECT q.[User], q.[DateTime]
 , q.Message
FROM
(
  SELECT t.[User], t.[DateTime], t.Message,
   COUNT(*) OVER (PARTITION BY t.[User], DATEADD(minute, DATEDIFF(minute, 0, DATEADD(s, 30, t.[DateTime])), 0)) AS Cnt
  FROM tbl t
  WHERE t.[User] = 'mfamoso'
) q
WHERE Cnt != 3
ORDER BY [DateTime] DESC;

只是这种查询不会检查一组3条消息是否不同。

答案 1 :(得分:0)

我会尝试以下类似方法。它需要使用临时表来添加字段(标识字段,PositionInSet和SetNum)。基本上,charindex用于识别三种潜在记录类型(导出,打印,清除)中的每一种,并且rownumber()用于根据它们在每个集合(第一,第二或第三种)中的预期位置将它们分组在一起。最后,返回记录计数<> 3的所有集合。

create table #t (
    UniqueID int identity(1,1),
    DateTime datetime,
    Message varchar(500),
    PositionInSet int,
    SetNum int
)

insert into #t (DateTime, Message)
    select '2019-03-11 12:55:00.097', '{"V":"1.0.0","In":"Program.Main()","E":"","D":"Exporting...."}'
    union all
    select '2019-03-11 12:55:00.270', '{"V":"1.0.0","In":"Program.Main()","E":"","D":"PreExportImprintHeader ran successfully"}'
    union all
    select '2019-03-11 12:55:08.543', '{"V":"1.0.0","In":"Program.Main()","E":"","D":"CleanUp ran successfully"}'

    union all
    select '2019-03-11 12:55:00.097', '{"V":"1.0.0","In":"Program.Main()","E":"","D":"Exporting...."}'
    union all
    select '2019-03-11 12:55:00.270', '{"V":"1.0.0","In":"Program.Main()","E":"","D":"PreExportImprintHeader ran successfully"}'

    union all
    select '2019-03-11 12:55:00.097', '{"V":"1.0.0","In":"Program.Main()","E":"","D":"Exporting...."}'
    union all
    select '2019-03-11 12:55:00.270', '{"V":"1.0.0","In":"Program.Main()","E":"","D":"PreExportImprintHeader ran successfully"}'
    union all
    select '2019-03-11 12:55:08.543', '{"V":"1.0.0","In":"Program.Main()","E":"","D":"CleanUp ran successfully"}'


/***********************************/

update #t
set PositionInSet = case
    when CHARINDEX('exporting', Message) <> 0 then 1
    when CHARINDEX('imprint', Message) <> 0 then 2
    when CHARINDEX('cleanup', Message) <> 0 then 3
end


update t
set t.SetNum = t2.SetNum
from (
    select
        DateTime,
        Message,
        PositionInSet,
        row_number() over (partition by PositionInSet order by UniqueID) as SetNum,
        UniqueID
    from #t
) t2
inner join #t t on t2.UniqueID = t.UniqueID


select * from #t
inner join (
    select
        COUNT(*) as Count,
        SetNum
    from #t
    group by SetNum
    having COUNT(*) <> 3
) grp on #t.SetNum = grp.SetNum

/***********************************/

答案 2 :(得分:0)

基本上,这种情况下的挑战是尝试对您的集合进行分组。由于您没有该集合的标识符,因此我们将不得不在10分钟之内依靠DateTime的接近度(或更短的距离,因为该过程需要不到一分钟或大约10秒的时间)。如果您在不到一分钟的时间内收到邮件,我们可以将其分组。当然,总有一种情况,您可以在一分钟内停止并启动该过程,这会打乱您的查询。

现在,请记住该分组,然后您可以查询3条消息中未包含的消息。

修改

对不起。我忘了这是SQL Server2008。您必须在这里使用自连接。

;with 
t0(dt,m,u,dtt) as (
-- no lead/lag in SQL Server 2008; use self join
select a.[DateTime], a.[Message], a.[User], c.[DateTime]
from t a
outer apply (select top 1 [DateTime] from t b where b.[DateTime]<a.[DateTime] order by b.[DateTime] desc) c
), 
t1(dt,m,u,nxt) as (
-- get the indicator where the difference in time is over 60 seconds
  select dt, m, u, case when isnull(datediff(ss,dtt,dt),0)<60 then 0 else 1 end
    from t0
),
t2(dt,m,u,groupid) as (
-- make the indicator into group id
select dt,m, u, sum(nxt) over (partition by 1 order by dt) 
from t1
),
t3(groupid) as (
-- filter out sets with less than 3 messages
select groupid
from t2
group by groupid
having count(*)<3
)
select t2.*
from t2
join t3 on t2.groupid=t3.groupid

原始

对于SQL Server 2012及更高版本:

;with t1(dt,m,u,nxt) as (
-- get the indicator where the difference in time is over 60 seconds
  select [DateTime], [Message], [User], case when isnull(datediff(ss,lag([DateTime]) over (order by [DateTime]),[DateTime]),0)<60 then 0 else 1 end
    from tbl
),
t2(dt,m,u,groupid) as (
-- make the indicator into group id
select dt,m, u, sum(nxt) over (partition by 1 order by dt) 
from t1
),
t3(groupid) as (
-- filter out sets with less than 3 messages
select a.groupid
from t2 a
group by a.groupid
having count(*)<3
)
select t2.*
from t2
join t3 on t2.groupid=t3.groupid
相关问题