问题
I have a sample data like this
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
From the above data set, if we only focus on ID='A' we note that A was initally active, then became inactive on 05-02-2000 and then it was inactive until 01-07-2000. 
Which means that A was inactive from 05-Feb-2000 to 01-July-2000.
My questions are:
if I execute a query with
(ID=A, Date=01-04-2000)it should give meA 05-02-2000 1000 INACTIVEbecause since that date is not available in that data set, it should search for the previous one and print that
Also, if my condition is
(ID=A, Date=01-07-2000)it should not only print the value which is present in the table, but also print a previous valueA 05-02-2000 1000 INACTIVE A 01-07-2000 1300 ACTIVE
I would really appreciate if any one can assist me solve this query. I am trying my best to solve this.
Thank you every one.
Any take on this?
Afaq
回答1:
Something like the following should work:
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
This will return at most two rows. Its not clear if you are using Date and Time datatyped columns, or if you are actually using reserved words as column names, so you'll have to fuss with that. (I left out Time, but you could easily add that to the various orderings and filterings.)
Given the revised criteria, it gets a bit trickier, as the inclusion or exclusion of a row depends upon the value returned in a different row. Here, the “second” row, if there are two or more rows, is included only if the “first” row equals a particular value. The standard way to do this is to query the data to get the max value, then query it again while referencing the result of the first set.
However, you can do a lot of screwy things with row_number. Work on this:
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
You'll have to resolve the date/time issue, since this only works against dates.
回答2:
Basically you need to pull a row if, for the specified date, it is:
1) the last record, or
2) the last inactive record.
And the two conditions may match the same row as well as two distinct rows.
Here's how this logic could be implemented in 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
    来源:https://stackoverflow.com/questions/10739147/printing-the-current-value-and-previous-value-between-the-date-range