2014-05-10 4 views
0

나는 월별 값이있는 테이블을 가지고 있으며이 값을 2 개월 단위로 분산시키는 주를 고려하여이 값을 스프레드의 각 부분에 반영해야한다고 생각합니다. 월 및 체중을 각 달에 해당하는 일 수로 나타냅니다.SQL 스프레드 월 값을 주 단위로 입력

예를 들어 나는

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 

을 다음과 같이 위에서보다시피 나는 주로 변환 할 필요가 달

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

가 겹치는 주 강철의 다른 가격으로 테이블이 1 월과 2 월 사이의 값은 다음과 같이 계산되어야합니다.

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

이것은 안녕 27 일주일은 1 월에 5 일, 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) 

추가로 7 이하 일 얻을 수있는 경우에 좀 더 날짜 계산을 할 만 월요일에 가입하고 단순화 할 수있다.

편집 :

귀하의 마지막 쿼리가 1월 31 일 두 번 반환, 당신은 on n.n < ndm.nd에서 =을 제거해야합니다. ISO 주간 작업을하는 것처럼 DATEFART 설정을 변경하면 문제가 발생하지 않도록 DATEPART를 변경하는 것이 좋습니다.

마지막 검색어를 기반으로 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

감사합니다. 귀하의 쿼리를 사용하려고하는 질문을 편집했지만 작동하지 않았습니다. – Selrac

+0

@Selrac : 쿼리를 기반으로 정확한 결과를 내기 위해 내 대답을 편집했습니다. – dnoeth

+0

감사합니다. 이것은 아주 훌륭합니다. 코드의 Beautifull 조각. 나는 그것이 어떻게 작동하는지 이해하지 못한다. 고마워, 대단히 !! – 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

감사합니다. 귀하의 쿼리를 사용하려고하는 질문을 편집했지만 작동하지 않았습니다. – Selrac

+0

이 댓글은 실제로 나에게 직접 전달되지 않았습니다. – dean

관련 문제