2014-05-10 41 views
0

我有一個表格,我有月份的價值,我希望按周分攤這些價值,同時考慮到延長到兩個月的星期需要接受每個月份的價值月和對應於每個月的天數的權重。SQL將月份價值分成幾周

比如我有一個不同的鋼材價格的表按月份

Product   Month  Price 
------------------------------------ 
Steel 1/Jan/2014 100 
Steel 1/Feb/2014 200 
Steel 1/Mar/2014 300 

我需要將其轉換成周如下

Product Week  Price 
------------------------------------------- 
Steel 06-Jan-14 100 
Steel 13-Jan-14 100 
Steel 20-Jan-14 100 
Steel 27-Jan-14 128.57 
Steel 03-Feb-14 200 
Steel 10-Feb-14 200 
Steel 17-Feb-14 200 

正如你看到的上面,重疊的一週在1月和2月之間需要計算如下

(100*5/7)+(200*2/7) 

這考慮到了t公頃27日的一週有5天,分爲1月和2月進入2月。

是否有任何可能的方式來創建一個查詢在SQL中可以實現這一點?

我嘗試以下

第一次嘗試:

select 
WD.week, 
PM.PRICE, 
DATEADD(m,1,PM.Month), 
SUM(PM.PRICE/7) * COUNT(*) 
from 
( select '2014-1-1' as Month, 100 as PRICE 
    union 
    select '2014-2-1' as Month, 200 as PRICE 
)PM 
join 
( select '2014-1-20' as week 
    union 
    select '2014-1-27' as week 
    union 
    select '2014-2-3' as week 
)WD 
ON WD.week>=PM.Month 
AND WD.week < DATEADD(m,1,PM.Month) 
group by 
WD.week,PM.PRICE, DATEADD(m,1,PM.Month) 

這給了我下面的

week PRICE 
2014-1-20 100 2014-02-01 00:00:00.000 14 
2014-1-27 100 2014-02-01 00:00:00.000 14 
2014-2-3 200 2014-03-01 00:00:00.000 28 

我也試過以下

;with x as (
    select price, 
     datepart(week,dateadd(day, n.n-2, t1.month)) wk, 
     dateadd(day, n.n-1, t1.month) dt 
    from 
    (select '2014-1-1' as Month, 100 as PRICE 
    union 
    select '2014-2-1' as Month, 200 as PRICE) t1 
    cross apply (
     select datediff(day, t.month, dateadd(month, 1, t.month)) nd 
     from 
     (select '2014-1-1' as Month, 100 as PRICE 
     union 
     select '2014-2-1' as Month, 200 as PRICE) 
     t 
     where t1.month = t.month) ndm 
    inner join 
     (SELECT (a.Number * 256) + b.Number AS N FROM 
     (SELECT number FROM master..spt_values WHERE type = 'P' AND number <= 255) a (Number), 
     (SELECT number FROM master..spt_values WHERE type = 'P' AND number <= 255) b (Number)) n --numbers 
    on n.n <= ndm.nd 
) 
select min(dt) as week, cast(sum(price)/count(*) as decimal(9,2)) as price 
from x 
group by wk 
having count(*) = 7 
order by wk 

這gimes我以下

week      price 
2014-01-07 00:00:00.000 100.00 
2014-01-14 00:00:00.000 100.00 
2014-01-21 00:00:00.000 100.00 
2014-02-04 00:00:00.000 200.00 
2014-02-11 00:00:00.000 200.00 
2014-02-18 00:00:00.000 200.00  

感謝

+1

您正在使用哪種RDBMS? MySQL的?甲骨文? SQL Server? ...? –

+0

我正在使用Microsoft SQL Server。對不起,我在 – Selrac

+0

Anup之前沒有提過,我嘗試過一些東西時有點失落。我得到的最接近的是當我試圖通過在星期表中添加一個「月」字段來加入一個星期的表。問題在於這不會在重疊星期內傳播價值。 – Selrac

回答

1

如果你有一個日曆表這是一個簡單的連接:

SELECT 
    product, 
    calendar_date - (day_of_week-1) AS week, 
    SUM(price/7) * COUNT(*) 
FROM prices AS p 
JOIN calendar AS c 
    ON c.calendar_date >= month 
AND c.calendar_date < DATEADD(m,1,month) 
GROUP BY product, 
    calendar_date - (day_of_week-1) 

這可以進一步簡化只能加入到星期一,然後做一個CASE一些日期計算得到小於或等於7天。

編輯:

你最後的查詢返回1月31日兩次,你需要從on n.n < ndm.nd刪除=。正如你似乎與ISO周工作,你最好改變DATEPART,以避免與不同DATEFIRST設置的問題。

根據您最後的查詢,我創建了一個fiddle

;with x as (
    select price, 
     datepart(isowk,dateadd(day, n.n, t1.month)) wk, 
     dateadd(day, n.n-1, t1.month) dt 
    from 
    (select '2014-1-1' as Month, 100.00 as PRICE 
    union 
    select '2014-2-1' as Month, 200.00 as PRICE) t1 
    cross apply (
     select datediff(day, t.month, dateadd(month, 1, t.month)) nd 
     from 
     (select '2014-1-1' as Month, 100.00 as PRICE 
     union 
     select '2014-2-1' as Month, 200.00 as PRICE) 
     t 
     where t1.month = t.month) ndm 
    inner join 
     (SELECT (a.Number * 256) + b.Number AS N FROM 
     (SELECT number FROM master..spt_values WHERE type = 'P' AND number <= 255) a (Number), 
     (SELECT number FROM master..spt_values WHERE type = 'P' AND number <= 255) b (Number)) n --numbers 
    on n.n < ndm.nd 
) select min(dt) as week, cast(sum(price)/count(*) as decimal(9,2)) as price 
from x 
group by wk 
having count(*) = 7 
order by wk 

當然日期可能是多年,所以你也需要年份GROUP BY。

+0

謝謝dnoeth。我編輯試圖使用您的查詢的問題,但它似乎並沒有工作。 – Selrac

+0

@Selrac:編輯我的答案,根據您的查詢產生正確的結果 – dnoeth

+0

謝謝dnoeth。這真是太神奇了。美麗的一段代碼。我不明白它是如何工作的。非常非常感謝! – Selrac

1

其實,你需要spred過來天,然後由周拿到的平均值。爲了得到這些日子,我們將使用Numbers table

;with x as (
    select product, price, 
     datepart(week,dateadd(day, n.n-2, t1.month)) wk, 
     dateadd(day, n.n-1, t1.month) dt 
    from #t t1 
    cross apply (
     select datediff(day, t.month, dateadd(month, 1, t.month)) nd 
     from #t t 
     where t1.month = t.month and t1.product = t.product) ndm 
    inner join numbers n on n.n <= ndm.nd 
) 
select product, min(dt) as week, cast(sum(price)/count(*) as decimal(9,2)) as price 
from x 
group by product, wk 
having count(*) = 7 
order by product, wk 

datepart(week,dateadd(day, n.n-2, t1.month))表達式的結果取決於SET DATEFIRST所以你可能需要相應地調整。

+0

謝謝dnoeth。我編輯試圖使用您的查詢的問題,但它似乎並沒有工作。 – Selrac

+0

這個評論並沒有真正指向我,是嗎? – dean