T-SQL查询以获取项目的先前价格,与当前价格的差异和先前价格的日期

时间:2011-02-06 01:20:32

标签: sql tsql sql-server-2008

Declare @sec_temp table 
(
 sec_no varchar(10),
 amount money,
 price_date date
)

insert @sec_temp
values
    ('123ABC', 25, '2011-01-20'), 
    ('123ABC', 25, '2011-01-19'), 
    ('123ABC', 25, '2011-01-18'), 
    ('123ABC', 20, '2011-01-17'),     
    ('123ABC', 20, '2011-01-15'),
    ('123ABC', 22, '2011-01-13'),
    ('456DEF', 22, '2011-01-13'),
    ('456DEF', 30, '2011-01-11')

问题:T-SQL查询获取项目的先前价格,与当前价格的差异和先前价格的日期。 “先前价格”定义为项目金额在当前金额之前发生变化的日期

结果:

**sec_no   current_Amount    Current_Price_Date   No_of_days_at_Current_price   prior_amount    prior_price_date   No_of_days_at_prior_price** 
123ABC       20              2011-01-20                      19                    20              2011-01-15             3

456DEF       22              2011-01-13                      24                    30              2011-01-11             2

当前代码(获取current_price_date和current_amount的数据):

(感谢cyberkiwi)

select
 sec_no,
 amount,
 No_of_days_at_price = 1 + DATEDIFF(d, min(price_date), max(price_date))
from (
    select *,
  ROW_NUMBER() over (partition by sec_no order by price_date desc) rn,
  ROW_NUMBER() over (partition by sec_no, amount order by price_date desc) rn2
    from @sec_temp
) X
WHERE rn=rn2
group by sec_no, amount

2 个答案:

答案 0 :(得分:3)

select
 X.sec_no,
 Current_Amount = X.amount,
 Current_Price_Date = X.price_date,
 No_of_days_at_current_price = DATEDIFF(d, X.price_date, getdate()),
 prior_amount = Y.amount,
 prior_price_date = Y.price_date,
 No_of_days_at_prior_price = DATEDIFF(d, Y.price_date, X.price_date)
from (
  select *,
  ROW_NUMBER() over (partition by sec_no order by price_date desc) rn
  from @sec_temp
) X
outer apply (
    select top(1) b.* from @sec_temp b
    where b.price_date < X.price_date and b.amount != X.amount
    and b.sec_no = X.sec_no
    order by b.price_date desc
    ) Y
WHERE rn=1

答案 1 :(得分:0)

另一种解决方案:

WITH grouped AS (
  SELECT
    *,
    price_duration = max_price_date - min_price_date + 1,
    rownum = ROW_NUMBER() OVER (PARTITION BY sec_no ORDER BY max_price_date DESC)
  FROM (
    SELECT
      sec_no,
      amount,
      min_price_date = MIN(price_date),
      max_price_date = MAX(price_date)
    FROM @sec_temp
    GROUP BY sec_no, amount
  ) s
)
SELECT
  g1.sec_no,
  current_Amount =              g1.amount,
  Current_Price_Date =          g1.max_price_date,
  No_of_days_at_Current_price = g1.price_duration,
  prior_amount =                g2.amount,
  prior_price_date =            g2.min_date_time,
  No_of_days_at_prior_price =   g2.price_duration
FROM grouped AS g1
  LEFT JOIN grouped AS g2 ON g1.sec_no = g2.sec_no AND g2.rownum = 2
WHERE g1.rownum = 1
ORDER BY g1.sec_no

如您所见,number of days的计算方式与当前脚本的完成方式略有不同。基本上它是相似的,它只是在分组后分配rownums ,而不是在查询之前。选择了不同的方式,因为rownums还用于将先前的价格数据与当前价格数据相结合。