2017-02-11 7 views
0

두 날짜 사이의 금액을 예측하려고합니다. 금액은 날짜 사이에 균등하게 분산되어 있습니다 (아래 표 참조). (잘하면) 단순해야합니까 - 어떤 아이디어입니까?SQL - 날짜 사이에 금액 배포

은 소스 테이블은 다음과 같습니다

+-----------+---------------+---------------+------+--------------+----------------+ 
| Project | Start Date | End Date | Days | Total Budget | Budget Per Day | 
+-----------+---------------+---------------+------+--------------+----------------+ 
| Project 1 | Jan. 01, 2017 | Apr. 11, 2017 | 100 |   100 | 1.00   | 
| Project 2 | Feb. 05, 2017 | Apr. 06, 2017 | 60 |   200 | 3.33   | 
| Project 3 | Feb. 03, 2017 | May. 03, 2017 | 89 |   50 | 0.56   | 
| Project 4 | Jan. 01, 2017 | Aug. 04, 2017 | 215 |   300 | 1.40   | 
+-----------+---------------+---------------+------+--------------+----------------+ 

결과 테이블은 다음과 같아야합니다

+-----------+---------------+--------+ 
| Project |  Day  | Budget | 
+-----------+---------------+--------+ 
| Project 1 | Jan. 01, 2017 | 1.00 | 
| Project 1 | Jan. 02, 2017 | 1.00 | 
| Project 1 | Jan. 03, 2017 | 1.00 | 
| Project 1 | Jan. 04, 2017 | 1.00 | 
| Project 1 | Jan. 05, 2017 | 1.00 | 
| …   | …    | …  | 
+-----------+---------------+--------+ 

사이드 참고 : 월별, 기준 : 목표는 다음 쉽게 다른 집계를하는 ​​것입니다 일년 중 처음 10 %의 예산의 10 %와 같은 다른 배포판 등이 있습니다. 최선을 다하는 방법에 대한 제안은 크게 감사 할 것입니다.

답변

1

먼저 자신에게 캘린더 테이블을 생성하십시오. 그들은 매우 유용합니다!

CREATE TABLE dbo.tCalendar(
    Date_Value DATE PRIMARY KEY NOT NULL, 
    Year AS (DATEPART(YEAR, Date_Value)) PERSISTED, 
    Month AS (DATEPART(MONTH, Date_Value)) PERSISTED, 
    Day AS (DATEPART(DAY, Date_Value)) PERSISTED, 
    Day_Of_Year AS (DATEPART(DY, Date_Value)) PERSISTED, 
) 

INSERT INTO dbo.tCalendar 
SELECT * 
FROM (
    SELECT DATEADD(DAY, ROW_NUMBER() OVER(ORDER BY (SELECT 1)) - 1, '2000-01-01') AS d 
    FROM  (VALUES(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1))v(n) 
    CROSS JOIN (VALUES(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1))w(n) 
    CROSS JOIN (VALUES(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1))x(n) 
    CROSS JOIN (VALUES(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1))y(n) 
) cal 
WHERE cal.d <= '2027-12-31' 

--SELECT * FROM dbo.tCalendar 

지금 당신은 단순히 JOIN 달력 테이블이 필요한 결과를 얻을 수 있습니다 더 복잡한 분포를 들어

CREATE TABLE #Project(
    Project VARCHAR(100) PRIMARY KEY NOT NULL, 
    Start_Date DATE, 
    End_Date DATE, 
    Days AS (DATEDIFF(DAY, Start_Date,End_Date) + 1) PERSISTED, 
    Total_Budget DECIMAL(19,2), 
    Budget_Per_Day AS (CAST(Total_Budget/(DATEDIFF(DAY, Start_Date,End_Date) + 1) AS DECIMAL(19,2))) PERSISTED 
) 

INSERT INTO #Project (Project, Start_Date, End_Date, Total_Budget) 
VALUES 
('Project 1', '2017-01-01', '2017-04-10', 100), 
('Project 2', '2017-02-05', '2017-04-05', 200), 
('Project 3', '2017-02-03', '2017-05-02', 50), 
('Project 4', '2017-01-01', '2017-08-03', 300) 

SELECT * 
FROM #Project 

SELECT p.Project 
     ,cal.Date_Value 
     ,p.Budget_Per_Day 
FROM #Project p 
    INNER JOIN dbo.tCalendar cal 
     ON cal.Date_Value BETWEEN p.Start_Date AND p.End_Date 

을 하나 개의 솔루션이 날짜 범위에 의해 저장 예산 할당에 테이블을 가지고있다, 예 :

CREATE TABLE #Project_Budget_Range(
    Project VARCHAR(100) NOT NULL, 
    Range_Start_Date DATE NOT NULL, 
    Range_End_Date DATE NOT NULL, 
    Range_Days AS (DATEDIFF(DAY, Range_Start_Date, Range_End_Date) + 1) PERSISTED, 
    Budget_Allocation_Value DECIMAL(19,0) NULL, 
    Budget_Allocation_Pct DECIMAL(9,4) NULL, 
    PRIMARY KEY (Project, Range_Start_Date), 
    -- End Date >= Start Date 
    CONSTRAINT CK_Range_Start_End_Date CHECK (Range_End_Date>=Range_Start_Date), 
    -- Either Budget_Allocation_Value or Budget_Allocation_Pct must have a value (but not both) 
    CONSTRAINT CK_Allocation_Type CHECK (Budget_Allocation_Value + Budget_Allocation_Pct IS NULL AND COALESCE(Budget_Allocation_Value,Budget_Allocation_Pct) IS NOT NULL) 
) 

INSERT INTO #Project_Budget_Range 
VALUES 
('Project 1', '2017-01-01', '2017-01-31', NULL, 0.5), 
('Project 1', '2017-02-01', '2017-02-28', 30, NULL), 
('Project 1', '2017-03-01', '2017-04-10', 20, NULL) 

SELECT * FROM #Project_Budget_Range 

SELECT p.Project 
     ,p.Total_Budget 
     ,cal.Date_Value 
     ,CAST(COALESCE( 
      (b.Budget_Allocation_Pct * p.Total_Budget)/b.Range_Days, -- Allocation by Pct 
      b.Budget_Allocation_Value/b.Range_Days -- Allocation by value 
     ) AS DECIMAL(19,8)) AS Budget_Allocation 
FROM #Project p 
    INNER JOIN #Project_Budget_Range b 
     ON p.Project = b.Project 
    INNER JOIN dbo.tCalendar cal 
     ON cal.Date_Value BETWEEN b.Range_Start_Date AND Range_End_Date 
WHERE p.Project = 'Project 1' 
; 

Sample output showing budget allocation by day

+0

당신에게 서지 감사 !!!!!! – FirstRedPepper

+0

모든 프로젝트가 동일한 기준을 사용하는 경우 - 처음 10 %는 예산의 10 %를 사용하고 나머지 50 %는 70 %를 사용하고 남은 40 %는 나머지 20 %의 예산을 사용합니다. 위의 코드? – FirstRedPepper