2017-08-04 6 views
1

問題

から複数の行を選択:私は列を持つテーブルでプロジェクトを保存し、私のSQLサーバー・2014年にタイムスパン

開始日 .. | 終了日 .... | プロジェクト名 ................. | ボリューム
2017-02-13 | 2017-04-12 | GenerateRevenue ......... | 20.02
2017-04-02 | 2018-01-01 | BuildRevenueGenerator | 300.044
2017-05-23 | | 2018-03-19 | Harvest Revenue ............ | 434.009

プロジェクトごとに1か月に1つの行を私に与えるにはSELECTが必要です。月の日を考慮する必要はありません。

日付 .......... | プロジェクト名 .................. | ボリューム
2017-02-01 | GenerateRevenue ......... | 20.02
2017-03-01 | GenerateRevenue ......... | 20.02
2017-04-01 | GenerateRevenue ......... | 20.02
2017-04-01 | BuildRevenueGenerator | 300.044
2017-05-01 | BuildRevenueGenerator | 300.044
2017-06-01 | BuildRevenueGenerator | 300.044
...

エクストラ

理想的にはSELECTのロジックは私の両方が、毎月のボリュームと、各月と以前との違いを計算することができます。

日付 .......... | プロジェクト名 .................. | VolumeMonthly
2017-02-01 | GenerateRevenue ......... | 6.6733
2017-03-01 | GenerateRevenue ......... | 6.6733
2017-04-01 | GenerateRevenue ......... | 6.6733
2017-04-01 | BuildRevenueGenerator | 30.0044
2017-05-01 | BuildRevenueGenerator | 30.0044
2017-06-01 | BuildRevenueGenerator | 30.0044
...また

...

は、私は、一時的なカレンダーのテーブルの上にマッピングすることができます知っているが、それは非常に高速肥大化と複雑になる傾向にあります。私は本当にこの問題を解決する良い方法を探しています。

ソリューション

ゴードンズソリューションは非常にうまく働いていたし、それはある種のカレンダー上の第二のテーブルまたはマッピングを必要としません。私は組合の両側が同じSELECTを持つように、いくつかの変更が必要でしたが。

ここに私の適応バージョン:

with cte as (
    select startdate as mondate, enddate, projectName, volume 
    from projects 
    union all 
    select dateadd(month, 1, mondate), enddate, projectName, volume 
    from cte 
    where eomonth(dateadd(month, 1, mondate)) <= eomonth(enddate) 
) 
select * from cte; 

ボリュームは毎月でボリュームを交換することによって達成することができます。

CAST(Cast(volume AS DECIMAL)/Cast(Datediff(month, 
startdate,enddate)+ 1 AS DECIMAL) AS DECIMAL(15, 2)) 
END AS [volumeMonthly] 
+3

私は赤ん坊のステップをお勧めします。 –

+1

サンプルデータと望ましい結果が役立ちます。あなたはまた、質問を簡素化する必要があります。 –

+0

ありがとうゴードン、そうです。私はあなたのようにいくつかのサンプルデータを追加しました。 – LeComte

答えて

0

あなたがに基づいて、各プロジェクトの行を展開する再帰サブクエリを使用することができます表:

with cte as (
     select stardate as mondate, p.* 
     from projects 
     union all 
     select dateadd(month, 1, mondate), . . . -- whatever columns you want here 
     from cte 
     where eomonth(dateadd(month, 1, mondate)) <= eomonth(enddate) 
    ) 
select * 
from cte; 

これは実際にあなたの質問に答えるかわかりません。最初に質問を読んだとき、私はテーブルがプロジェクトごとに1行あると考えました。

+0

はい、あなたは正しいです、プロジェクトごとに1つの行があります – LeComte

1

別のオプションは、アドホック集計テーブルである

-- Some Sample Data 
Declare @YourTable table (StartDate date,EndDate date,ProjectName varchar(50), Volume float) 
Insert Into @YourTable values 
('2017-03-15','2017-07-25','Project X',25) 
,('2017-04-01','2017-06-30','Project Y',50) 

-- Set Your Desired Date Range 
Declare @Date1 date = '2017-01-01' 
Declare @Date2 date = '2017-12-31' 

Select Period = D 
     ,B.* 
     ,MonthlyVolume = sum(Volume) over (Partition By convert(varchar(6),D,112)) 
From (Select Top (DateDiff(MONTH,@Date1,@Date2)+1) D=DateAdd(MONTH,-1+Row_Number() Over (Order By (Select Null)),@Date1) 
     From master..spt_values n1 
    ) A 
Join @YourTable B on convert(varchar(6),D,112) between convert(varchar(6),StartDate,112) and convert(varchar(6),EndDate,112) 
Order by Period,ProjectName 

戻り

enter image description here

注:SEに使用LEFT JOINを電子ギャップヶ月間common table expressions、アドホックカレンダーのテーブルのカップルを使用して

0

lag()最終delta計算に(SQL Serverの2012+):

create table projects (id int identity(1,1), StartDate date, EndDate date, ProjectName varchar(32), Volume float); 
insert into projects values ('20170101','20170330','SO Q1',240),('20170214','20170601','EX Q2',120) 

declare @StartDate date = '20170101' 
     , @EndDate date = '20170731'; 
;with Months as (
    select top (datediff(month,@startdate,@enddate)+1) 
     MonthStart = dateadd(month, row_number() over (order by number) -1, @StartDate) 
     , MonthEnd = dateadd(day,-1,dateadd(month, row_number() over (order by number), @StartDate)) 
    from master.dbo.spt_values 
) 
, ProjectMonthlyVolume as (
    select p.* 
    , MonthlyVolume = Volume/(datediff(month,p.StartDate,p.EndDate)+1) 
    , m.MonthStart 
    from Months m 
    left join Projects p 
     on p.EndDate >= m.MonthStart 
    and p.StartDate <= m.MonthEnd 
) 
select 
    MonthStart = convert(char(7),MonthStart,120) 
    , MonthlyVolume = isnull(sum(MonthlyVolume),0) 
    , Delta = isnull(sum(MonthlyVolume),0) - lag(Sum(MonthlyVolume)) over (order by MonthStart) 
from ProjectMonthlyVolume pmv 
group by MonthStart 

rextesterデモ:http://rextester.com/DZL54787

リターン:

+------------+---------------+-------+ 
| MonthStart | MonthlyVolume | Delta | 
+------------+---------------+-------+ 
| 2017-01 |   80 | NULL | 
| 2017-02 |   104 | 24 | 
| 2017-03 |   104 | 0  | 
| 2017-04 |   24 | -80 | 
| 2017-05 |   24 | 0  | 
| 2017-06 |   24 | 0  | 
| 2017-07 |    0 | -24 | 
+------------+---------------+-------+ 
関連する問題