从一组运行值中选择最旧和最新值

时间:2013-02-13 20:59:26

标签: sql-server-2008

我正在尝试使用MSSQL 2008在指定的日期窗口中获取最新且最新的运行值(缺少更好的术语),并且我正在努力。这是表格的样子:

Job      Date         Percent_complete
---      ----         ----------------
1        1/5/2013     5
2        1/10/2013    5
2        1/25/2013    15
2        2/15/2013    25
3        2/15/2013    5
1        2/10/2013    10
1        2/23/2013    20
1        2/24/2013    18
4        1/12/2013    40

例如,在我的查询中,我想询问2013年2月1日至2013年2月28日最旧和最新的percent_complete并获取:

Job   Old    New
---   ---    ---
1     5      18
2     15     25
3     0      5
4     40     40

...所以这里的问题是,开始日期之前的最后一个percent_complete值必须结转,如果没有记录(例如作业3),则需要假设为0.此外,该数字可能会倒退从它的高位开始,就像在工作1中那样......所以min(complete)max(complete)不会让我们在那里。此外,我在作业4中添加了一条记录,以说明报告窗口中没有记录时的预期结果。

2 个答案:

答案 0 :(得分:2)

我可以用这样的结果得到结果:

with max_percent as
(
  select Job
    , [Max] = max(Percent_complete)
  from jobs
  where [Date] between '2/1/2013' and '2/28/2013'
  group by Job
),
min_percent as
(
  select Job
    , [Max] = max(Percent_complete)
  from jobs
  where [Date] < '2/1/2013'
  group by Job
)
select Job = coalesce(mn.Job, mx.Job)
  , [Min] = case when mx.Job is not null then mn.[Max] else 0 end
  , [Max] = coalesce(mx.[Max], mn.[Max], 0)
from max_percent mx
  full join min_percent mn on mx.Job = mn.Job
order by Job

SQL Fiddle demo

但是要理解您的要求有点困难,所以我不确定这对所有情况下的数据都有效。如果您在问题中添加更多数据和预期结果,我可以根据需要进行更新。

评论后修改:

这个新查询给出了您所追求的结果:

with jobList as
(
  select distinct Job from jobs
)
select Job
  , [Min] = isnull(case when mx.[Max] is not null then mn.[Max] else 0 end, 0)
  , [Max] = coalesce(mx.[Max], mn.[Max], 0)

from jobList jl
  outer apply
  (
    select top 1 [Max] = j.Percent_complete
    from jobs j
    where [Date] between '2/1/2013' and '2/28/2013'
      and jl.Job = j.Job
    order by j.[Date] desc
  ) mx
  outer apply
  (
    select top 1 [Max] = j.Percent_complete
    from jobs j
    where [Date] < '2/1/2013'
      and jl.Job = j.Job
    order by j.[Date] desc
  ) mn
order by jl.Job

SQL Fiddle with demo

同样,它仅针对一个小数据集,但它按日期取得最高值而不是最大百分比,所以希望能让你朝着正确的方向前进。

第二次修改:

只需稍微更改查询即可获得新结果:

with jobList as
(
  select distinct Job from jobs
)
select Job
  , [Min] = isnull(mn.[Max], 0)
  , [Max] = coalesce(mx.[Max], mn.[Max], 0)

from jobList jl
  outer apply
  (
    select top 1 [Max] = j.Percent_complete
    from jobs j
    where [Date] between '2/1/2013' and '2/28/2013'
      and jl.Job = j.Job
    order by j.[Date] desc
  ) mx
  outer apply
  (
    select top 1 [Max] = j.Percent_complete
    from jobs j
    where [Date] < '2/1/2013'
      and jl.Job = j.Job
    order by j.[Date] desc
  ) mn
order by jl.Job

SQL Fiddle with demo

答案 1 :(得分:0)

这是另一种方法:

步骤1。选择行Date值不晚于所选月份的行,将每个作业的数据拆分为两个分区:所选月份数据进入New分区其余的进入Old

应用于您的示例,这将生成以下结果集:

Job  Date       Percent_complete  recency
---  ----       ----------------  -------
1    1/5/2013   5                 Old    
2    1/10/2013  5                 Old    
2    1/25/2013  15                Old    
2    2/15/2013  25                New    
3    1/15/2013  5                 New    
1    2/10/2013  10                New    
1    2/23/2013  20                New    
1    2/24/2013  18                New    
4    1/12/2013  40                Old    

第2步。Date的降序对每个分区中的行进行排名:

Job  Date       Percent_complete  recency  rnk
---  ----       ----------------  -------  ---
1    1/5/2013   5                 Old      1  
2    1/10/2013  5                 Old      2  
2    1/25/2013  15                Old      1  
2    2/15/2013  25                New      1  
3    1/15/2013  5                 New      1  
1    2/10/2013  10                New      3  
1    2/23/2013  20                New      2  
1    2/24/2013  18                New      1  
4    1/12/2013  40                Old      1  

第3步。仅获取排名为1的行:

Job  Date       Percent_complete  recency  rnk
---  ----       ----------------  -------  ---
1    1/5/2013   5                 Old      1
2    1/25/2013  15                Old      1
2    2/15/2013  25                New      1
3    1/15/2013  5                 New      1
1    2/24/2013  18                New      1

第4步。转动百分比并将任何Old NULL默认为0,将New默认为Old

Job  Old  New
---  ---  ---
1    5    18
2    15   25
3    0    5

以下查询实现了上述逻辑:

WITH partitioned AS (
  SELECT
    Job,
    Date,
    Percent_complete,
    recency = CASE
      WHEN Date >= '20130201' THEN 'NEW'
      ELSE 'Old'
    END
  FROM atable
  WHERE Date < '20130301'
)
, ranked AS (
  SELECT
    Job,
    Date,
    Percent_complete,
    recency,
    rnk = ROW_NUMBER() OVER (PARTITION BY Job, recency ORDER BY Date DESC)
  FROM partitioned
)
, filtered AS (
  SELECT
    Job,
    Percent_complete,
    recency
  FROM ranked
  WHERE rnk = 1
)
, pivoted AS (
  SELECT
    Job,
    Old = ISNULL(Old, 0),
    New = ISNULL(New, Old)
  FROM filtered
  PIVOT (
    MAX(Percent_complete) FOR recency IN (Old, New)
  ) u
)
SELECT *
FROM pivoted
;

您可以测试此查询at SQL Fiddle