SQL Server - 根据ID和计算机名查找上一条记录

时间:2015-04-16 18:49:51

标签: sql sql-server-2008 tsql

我有两张表,其中包含来自多台不同计算机的警报信息。我想返回特定计算机的特定警报列表,还包括该计算机的先前警报。

表1:计算机信息

  ComputerInfoId| ComputerName| [Desc]
        1       |  Desktop1   | Front Desk
        2       |  Laptop1    | Work Station 1

表2:AlarmData

AlarmDataId|ComputerInfoId|AlarmId|AlarmDate
     1          2             1     03Mar2014 01:12:29
     2          2             3     03Mar2014 01:12:30
     3          1             7     03Mar2014 01:12:33
     4          1             2     03Mar2014 01:12:36
     5          1             6     03Mar2014 01:14:29
     6          2            12     03Mar2014 01:15:30
     7          1             2     03Mar2014 01:16:12
     8          2             1     03Mar2014 01:19:40

我想查询ComputerInfoID 1和AlarmId 2.查询将返回这些记录以及之前发生的该站的2条记录。

预期数据:

ComputerInfoId|ComputerName|AlarmDataId|AlarmId|     AlarmDate    
      1       |  Desktop1  |    3      |  7    |03Mar2014 01:12:33 --Prev Record
      1       |  Desktop1  |    4      |  2    |03Mar2014 01:12:36 --Record fits Criteria
      1       |  Desktop1  |    5      |  6    |03Mar2014 01:14:29 --Prev Record
      1       |  Desktop1  |    7      |  2    |03Mar2014 01:16:12 --Record fist Criteria

输出数据中不需要每行后面的注释,为清楚起见,它们包含在此处。

我一直在使用的查询是:

 SELECT * 
 FROM AlarmData AD LEFT OUTER JOIN 
        (SELECT *
         FROM   AlarmData AD2 INNER JOIN 
                 (SELECT  MAX(AlarmDatId)[MaxADID]
                  FROM    AlarmData AD3
                  WHERE   AD3.AlarmDataId < AD.AlarmDataId 
                         AND AD3.ComputerInfoID = AD.ComputerInfoID) AMax
           ON AD2.AlarmDataId = AMax.MaxADID) PrevAl
             ON PrevAl.ComputerInfoID = AD.ComputerInfoID 
 WHERE AD.ComputerInfoID = 1 AND AD.AlarmId = 2

但是我收到的错误是AD.AlarmDataId和AD.ComputerInfoID无法绑定在&#34; AD3.AlarmDataId&lt; AD.AlarmDataId AND AD3.ComputerInfoID = AD.ComputerInfoID&#34;线。

5 个答案:

答案 0 :(得分:1)

您的样本输出数据与输入数据不匹配,我无法判断您是否希望每个匹配错误有两个先前的错误,或者样本数据中每个错误的前一个错误。我认为此查询将适用于较大的数据集,其中机器的上一个警报可能不是之前的AlarmDataID。

我已在评论中指出了哪里可以更改您选择的周围行数。

with Errors  as (
select *, ROW_NUMBER() over( order by alarmdate) as OrdCnt
from alarmdata AD
  WHERE AD.ComputerInfoID = 1
)
select c.ComputerName, f.*
from ComputerInfo c 
    left outer join errors e
        on c.computerInfoId = e.ComputerInfoID 
    left outer join errors f
        on f.OrdCnt between (e.OrdCnt - 1 )and (e.OrdCnt + 0) -- Number of rows before and after
where (e.AlarmID = 2)

答案 1 :(得分:1)

我认为这对你有用:

Select ComputerInfo.ComputerInfoId ,ComputerInfo.ComputerName
      ,AlarmData.AlarmDataId ,AlarmData.AlarmId ,AlarmData.AlarmDate
      ,TB.AlarmId As PreAlarmId ,TB.AlarmDate As PreAlarmDate

From ComputerInfo
inner join AlarmData On AlarmData.ComputerInfoId =ComputerInfo.ComputerInfoId
Left Outer join AlarmData TB 
                          On TB.ComputerInfoId = ComputerInfo.ComputerInfoId
                         And TB.AlarmDataId < AlarmData.AlarmDataId
                         And TB.AlarmDataId in ( Select Max(a_1.AlarmDataId)  From AlarmData As a_1
                                                        Where a_1.ComputerInfoId = ComputerInfo.ComputerInfoId
                                                        And a_1.AlarmDataId < AlarmData.AlarmDataId)
where ComputerInfo.ComputerInfoId = 1
And AlarmData.AlarmId = 2

这是sql小提琴链接:Sql Fiddle Link

答案 2 :(得分:0)

您的结果不清楚(AlarmDataId = 5适用于ComputerInfoId = 2 NOT 1)

但是我写了一些希望就是你需要的东西

SELECT a.ComputerInfoID, 
       (SELECT ComputerName 
         FROM ComputerInfo c 
         WHERE c.ComputeInfoID = a.ComputerInfoID),
       a.AlarmDataId, a.AlarmId, a.AlarmDate
FROM AlarmData a
WHERE a.ComputerInfoID = 1 
AND ( a.AlarmId = 2
      OR EXISTS ( SELECT 'a'
                  FROM AlarmData a2
                  WHERE a.ComputerInfoID = a2.ComputerInfoID
                  AND a2.AlarmId = 2
                  AND a2.AlarmDate > a.AlarmDate
                  AND NOT EXISTS ( SELECT 'b'
                                   FROM AlarmData a3
                                   WHERE a.ComputerInfoID = a3.ComputerInfoID
                                   AND a3.AlarmDate < a2.AlarmDate
                                   AND a3.AlarmDate > a.AlarmDate
                                  )
                )
     )

答案 3 :(得分:0)

我也试过了。我为它创建了一个SQLFiddle

要注意的事情。您可以设置它返回的深度以显示错误,因此您可以通过简单地将深度增加到2来显示最后两个错误,而不是仅显示最后两个错误:

cte.Depth + 1 <= 1 -- Depth you want to go to

在这里

alarms.Depth <= 1 -- Should equal the depth in the CTE query

运行此查询时,它会提供以下结果集:

ComputerInfoId  ComputerName    AlarmDataId AlarmId AlarmDate
1               Desktop1        3           7       2014-03-03 01:12:33.000
1               Desktop1        4           2       2014-03-03 01:12:36.000
1               Desktop1        6           12      2014-03-03 01:15:30.000
1               Desktop1        7           2       2014-03-03 01:16:12.000

答案 4 :(得分:0)

您可以将此查询用于预期输出

WITH cte
AS (
    SELECT AD.ComputerInfoId
        ,ComputerName
        ,AlarmDataId
        ,AlarmId
        ,AlarmDate
    FROM AlarmData AD
    INNER JOIN ComputerInfo C ON AD.ComputerInfoId = C.ComputerInfoId
    WHERE AD.ComputerInfoId = 1
        AND AlarmId <> 2
    )
SELECT ComputerInfoId
    ,ComputerName
    ,AlarmDataId
    ,AlarmId
    ,AlarmDate
FROM cte
WHERE AlarmDataId < (
        SELECT Max(AlarmDataId)
        FROM AlarmData
        WHERE ComputerInfoId = 1
            AND AlarmId = 2
        )

UNION ALL

SELECT AD.ComputerInfoId
    ,ComputerName
    ,AlarmDataId
    ,AlarmId
    ,AlarmDate
FROM AlarmData AD
INNER JOIN ComputerInfo C ON AD.ComputerInfoId = C.ComputerInfoId
WHERE AD.ComputerInfoId = 1
    AND AlarmId = 2
ORDER BY AlarmDataId