Reputation: 449
I have two tables:
first one (amount):
amountid date amount
1 01.01.2011 100
2 02.01.2011 50
3 04.01.2011 200
4 10.01.2011 20
5 11.01.2011 5
second one (period):
periodid date
1 01.01.2011
2 03.01.2011
3 05.01.2011
I need group first table by times from second table, and sum (amount):
for this example answer is:
01.01.2011 150
03.01.2011 200
05.01.2011 25
help me with sql query please.
Upvotes: 1
Views: 134
Reputation: 138990
Sample data
declare @Amount table
(
amountid int,
[date] datetime,
amount int
)
declare @Period table
(
periodid int,
[date] datetime
)
insert into @Amount
select 1, '20110101', 100 union all
select 2, '20110102', 50 union all
select 3, '20110104', 200 union all
select 4, '20110110', 20 union all
select 5, '20110111', 5
insert into @Period
select 1, '20110101' union all
select 2, '20110103' union all
select 3, '20110105'
The query
select P.StartDate,
sum(A.amount) as amount
from (
select P1.[date] as StartDate,
coalesce((select min(P2.[date])
from @Period as P2
where P1.[date] < P2.[date]), '99991231') as endDate
from @Period as P1
) as P
inner join @Amount as A
on A.[date] >= P.StartDate and
A.[date] < P.EndDate
group by P.StartDate
Upvotes: 3
Reputation: 449
For now i have this sql-s from other forum:
declare @t table
( amountid int,date smalldatetime,amount int)
declare @p table (periodid int,date smalldatetime)
Insert into @t
Select 1,'2011-01-01', 100
union all
Select 2,'2011-01-02', 50
union all
Select 3,'2011-01-04', 200
union all
Select 4,'2011-01-10', 20
union all
Select 5,'2011-01-11', 5
Insert into @p
Select 1, '2011-01-01'
union all
Select 2, '2011-01-03'
union all
Select 3, '2011-01-05'
Select p.date, sum(t.amount) from
@P p
inner join
@t t on
p.date <= t.Date
where
not exists
( select top 1 1 from @p pp where pp.Date > p.Date and pp.Date < t.Date)
group by p.Date
if i am right, this have best plan when i do "show execution plan" on my server.
Am i right?
Upvotes: 0
Reputation: 2855
The query to compute the enddates for the periods is
select P1.periodid, P1.date as startdate, min(P2.date) as enddate
from period P1
left outer join period P2 on P2.date > P1.date
group by P1.periodid, P1.date
results
PERIODID STARTDATE ENDDATE
1 2011-01-01 2011-01-03
2 2011-01-03 2011-01-05
3 2011-01-05 NULL
With the use of that you can sum all the amounts for all periods like this
select P.periodid, P.startdate, P.enddate, sum(A.amount) as sum
from (
select P1.periodid, P1.date as startdate, min(P2.date) as enddate
from period P1
left outer join period P2 on P2.date > P1.date
group by P1.periodid, P1.date
) P
left outer join amount A
on A.date >= P.startdate and (P.enddate is null or A.date < P.enddate)
group by P.periodid, P.startdate, P.enddate
results
PERIODID STARTDATE ENDDATE SUM
1 2011-01-01 2011-01-03 150
2 2011-01-03 2011-01-05 200
3 2011-01-05 NULL 25
Upvotes: 1
Reputation: 1815
create table #amount (
amountid int,
[date] datetime,
amount int
)
create table #period (
periodid int,
[date] datetime
)
delete from #amount
delete from #period
insert into #amount
values (1, {d '2011-01-01'}, 100),
(2, {d '2011-01-02'}, 50),
(3, {d '2011-01-04'}, 200),
(4, {d '2011-01-10'}, 20),
(5, {d '2011-01-11'}, 5)
insert into #period
values (1, {d '2011-01-01'}),
(2, {d '2011-01-03'}),
(3, {d '2011-01-05'})
select p.date, SUM(a.amount) as amount
from #period p inner join
(
select a.amountid, MAX(p.periodid) as periodid
from #amount a inner join
#period p on a.date >= p.date
group by a.amountid
) mp on p.periodid = mp.periodid inner join
#amount a on mp.amountid = a.amountid
group by p.date
It would certainly be easier if your period table could have an end date.
Upvotes: 0