1

我有这样的样本数据

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-2000到处于非活动状态01-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 
    

如果有人能帮助我解决这个问题,我将不胜感激。我正在尽力解决这个问题。

谢谢大家。

对此有何看法?

阿法克

4

2 回答 2

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

这将最多返回两行。不清楚您是使用日期和时间数据类型的列,还是实际上使用保留字作为列名,所以您必须对此大惊小怪。(我省略了时间,但您可以轻松地将其添加到各种排序和过滤中。)


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

但是,您可以使用 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

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

于 2012-05-24T14:22:05.717 回答
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
于 2012-05-25T06:21:14.627 回答