打印日期范围之间的当前值和先前值

时间:2012-05-24 14:09:25

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

我有这样的样本数据

ID     DATE           TIME     STATUS 
---------------------------------------------
A      01-01-2000     0900     ACTIVE 
A      05-02-2000     1000     INACTIVE 
A      01-07-2000     1300     ACTIVE 
B      01-05-2005     1000     ACTIVE 
B      01-08-2007     1050     ACTIVE
C      01-01-2010     0900     ACTIVE 
C      01-07-2010     1900     INACTIVE

从上面的数据集中,如果我们只关注ID='A',我们会注意到A最初处于活动状态,然后在05-02-2000上变为非活动状态,然后在01-07-2000之前处于非活动状态}。

这意味着A05-Feb-200001-July-2000无效。

我的问题是:

  1. 如果我使用(ID=A, Date=01-04-2000)执行查询,它应该给我

    A      05-02-2000     1000     INACTIVE 
    

    因为该日期在该数据集中不可用,所以它应该搜索前一个并打印出来

  2. 此外,如果我的条件是(ID=A, Date=01-07-2000),它不仅应该打印表中存在的值,还应该打印先前的值

    A      05-02-2000     1000     INACTIVE 
    A      01-07-2000     1300     ACTIVE 
    
  3. 如果有人能帮我解决这个问题,我真的很感激。我正在尽力解决这个问题。

    谢谢大家。

    对此有何看法?

    AFAQ

2 个答案:

答案 0 :(得分:1)

以下内容应该有效:

SELECT ID, Date, Time, Status
 from (select ID, Date, Time, Status, row_number() over (order by Date) Ranking
        from MyTable
        where ID = @SearchId
         and Date <= @SearchDate) xx
 where Ranking < 3
 order by Date, Time

这将最多返回两行。不清楚你是否使用Date和Time数据类型列,或者如果你实际上使用保留字作为列名,那么你将不得不大惊小怪。 (我遗漏了时间,但您可以轻松地将其添加到各种排序和过滤中。)


鉴于修订后的标准,它会变得有点棘手,因为包含或排除行取决于在不同行中返回的值。这里,仅当“第一”行等于特定值时,才包括“第二”行(如果存在两行或更多行)。执行此操作的标准方法是查询数据以获取最大值,然后在引用第一组结果时再次查询数据。

但是,你可以使用row_number做很多棘手的事情。这方面的工作:

SELECT ID, Date, Time, Status
 from (select
          ID, Date, Time, Status
         ,row_number() over (partition by case when Date = @SearchDate then 0 else 1 end
                             order by     case when Date = @SearchDate then 0 else 1 end
                                         ,Date) Ranking
        from MyTable
        where ID = @SearchId
         and Date <= @SearchDate) xx
 where Ranking = 1
 order by Date, Time

您必须解决日期/时间问题,因为这只适用于日期。

答案 1 :(得分:0)

基本上,如果在指定日期它是:

,则需要拉一行

1)最后一条记录,或

2)最后无效记录。

这两个条件可能匹配同一行以及两个不同的行。

以下是如何在SQL Server 2005 +中实现此逻辑:

WITH ranked AS (
  SELECT
    ID,
    Date,
    Time,
    Status,
    RankOverall  = ROW_NUMBER() OVER (                    ORDER BY Date DESC),
    RankByStatus = ROW_NUMBER() OVER (PARTITION BY Status ORDER BY Date DESC)
  FROM Activity
  WHERE ID = @ID
    AND Date <= @Date
)
SELECT
  ID,
  Date,
  Time,
  Status,
FROM ranked
WHERE RankOverall = 1
   OR Status = 'INACTIVE' AND RankByStatus = 1