如果在另一行的特定时间段内获得一行

时间:2013-08-09 19:04:35

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

我有一个SQL语句,我目前正在使用它来从数据库中返回许多行:

SELECT
    as1.AssetTagID, as1.TagID, as1.CategoryID,
    as1.Description, as1.HomeLocationID, as1.ParentAssetTagID
FROM Assets AS as1
    INNER JOIN AssetsReads AS ar  ON as1.AssetTagID = ar.AssetTagID
WHERE
    (ar.ReadPointLocationID='Readpoint1' OR ar.ReadPointLocationID='Readpoint2')
    AND (ar.DateScanned between 'LastScan' AND 'Now')
    AND as1.TagID!='000000000000000000000000'

我想要执行一个查询,该查询将从此查询获取具有最早DateScanned的行,并且如果在该行的某个特定时间段内存在一行,则还从数据库获取另一行(比如说5秒钟。通过以降序排序选择第一条记录,最旧的记录会相对简单,但如果第二条记录在第一条记录的某个时间段内,我怎么能得到第二条记录呢?

我知道我可以使用多个查询执行此过程,但有没有办法将此过程合并到一个查询中?

我使用的数据库是SQL Server 2008 R2。

另请注意,DateScanned次只是占位符,我将在将使用此查询的应用程序中处理此问题。

2 个答案:

答案 0 :(得分:1)

我不确定sql server语法,但你可以做这样的事情

SELECT * FROM (
  SELECT 
    TOP 2
    as1.AssetTagID, 
    as1.TagID, 
    as1.CategoryID, 
    as1.Description, 
    as1.HomeLocationID, 
    as1.ParentAssetTagID ,
    ar.DateScanned,
    LAG(ar.DateScanned) OVER (order by ar.DateScanned desc) AS lagging
  FROM 
    Assets AS as1
    INNER JOIN AssetsReads AS ar
      ON as1.AssetTagID = ar.AssetTagID
  WHERE (ar.ReadPointLocationID='Readpoint1' OR ar.ReadPointLocationID='Readpoint2')
    AND (ar.DateScanned between 'LastScan' AND 'Now')
    AND as1.TagID!='000000000000000000000000'
  ORDER BY
    ar.DateScanned DESC  
)
WHERE 
  lagging IS NULL or DateScanned - lagging < '5 SECONDS'

我尝试按DateScanned desc排序结果,然后排在最前面的2行。然后我在DateScanned字段上使用lag()函数来获取前一行的DateScanned值。对于最上面的行,DateScanned应为null作为其第一个记录,但对于第二个记录,它应为第一行的值。然后,您可以比较这两个值以确定是否要显示第二行

滞后函数

更多信息http://blog.sqlauthority.com/2011/11/15/sql-server-introduction-to-lead-and-lag-analytic-functions-introduced-in-sql-server-2012/

答案 1 :(得分:1)

这是一种相当普遍的方法。使用min()作为窗口函数获取最早的扫描日期,然后使用日期算法获取您想要的任何行:

select t.*  -- or whatever fields you want
from (SELECT as1.AssetTagID, as1.TagID, as1.CategoryID,
             as1.Description, as1.HomeLocationID, as1.ParentAssetTagID,
             min(DateScanned) over () as minDateScanned, DateScanned
      FROM Assets AS as1
           INNER JOIN AssetsReads AS ar  ON as1.AssetTagID = ar.AssetTagID
      WHERE (ar.ReadPointLocationID='Readpoint1' OR ar.ReadPointLocationID='Readpoint2')
            AND (ar.DateScanned between 'LastScan' AND 'Now')
            AND as1.TagID!='000000000000000000000000'
     ) t
where datediff(second, minDateScanned, DateScanned) <= 5;