I'd like to get some help with a code, I want to get the average Price per City and per Year from TableA that holds data from the last three years.
TableA
Date City Price
10/23/2018 Leon 1088
2/27/2018 NewYork 1312
4/19/2017 Texas 1303
4/19/2017 London 1303
4/19/2019 NewYork 1303
2/12/2018 Leon 1251
4/7/2017 Leon 1170
3/20/2019 London 1650
12/18/2017 Texas 1358
2/18/2019 Leon 1088
7/3/2017 NewYork 1391
8/8/2019 Texas 830
4/5/2018 London 1869.5
1/29/2018 London 1169
8/9/2019 Texas 1130
Average price should be calculated per city per year. Results should be grouped by year and shown per each City as follows:
Result from TableA
City Avg2017 Avg2018 Avg2019
Leon 1170 1169.5 1088
London 1303 1519.25 1650
New York 1391 1312 1303
Texas 1330.5 0 1390
However I want it to automatically process future data and that when 2020 comes then 2017 disappears from the results (and so on for further years).
The scenario would be something like:
TableB
Date City Price
10/23/2018 Leon 1088
2/27/2018 NewYork 1312
4/19/2020 Texas 1303
4/19/2020 London 1303
4/19/2019 NewYork 1303
2/12/2018 Leon 1251
4/7/2020 Leon 1170
3/20/2019 London 1650
12/18/2020 Texas 1358
2/18/2019 Leon 1088
7/3/2020 NewYork 1391
8/8/2019 Texas 830
4/5/2018 London 1869.5
1/29/2018 London 1169
8/9/2019 Texas 1130
4/19/2017 Texas 1303
4/19/2017 London 1303
4/7/2017 Leon 1170
12/18/2017 Texas 1358
7/3/2017 NewYork 1391
And the result without 2017 and with 2020.
Result from TableB
City Avg2018 Avg2019 Avg2020
Leon 1169.5 1088 1170
London 1519.25 1650 1303
New York 1312 1303 1391
Texas 0 1390 1330.5
My SQL Server version is 15.0.18142
Is this possible?
For dynamic year pivoting
, our only option is to use dynamic queries.
getting the last 3 years of data
between dateadd(yy, -3, getdate()) and getdate()
full query:
select * into #res from (
select '10/23/2018' as d ,'Leon' City, 1088 as price
union all
select '2/27/2018' ,'NewYork' ,1312
union all
select '4/19/2017' ,'Texas' ,1303
union all
select '4/19/2017' ,'Leon' ,1303
union all
select '4/19/2019' ,'London' ,1303
union all
select '4/19/2019' ,'NewYork' ,2000
union all
select '3/19/2019' ,'NewYork' ,1000
union all
select '3/19/2020' ,'NewYork' ,1000
union all
select '3/19/2020' ,'London' ,3000
union all
select '3/19/2020' ,'Texas' ,1000
)res
declare @cols nvarchar(max);
declare @sql nvarchar(max);
select @cols =
stuff((select N'],[Avg' + d
from (select distinct right(d, 4) as d
from #res where right(d, 4) between year(getdate())-1 and year(getdate())+1) AS t1
for xml path('')
), 1, 2, '') + N']';
set @sql = N'Select City, ' + @cols + N'
from (select City, concat(''Avg'', right(d, 4)) as d, price from #res)t1
pivot
(
avg(t1.price)
for t1.d in (' + @cols + N')
) p
'
print @sql;
exec sp_executesql @sql;
drop table #res
You can do conditional aggregation:
select
city,
avg(case when [date] >= date('2017-01-01') and [date] < date('2018-01-01') then price end) avg2017,
avg(case when [date] >= date('2018-01-01') and [date] < date('2019-01-01') then price end) avg2018,
avg(case when [date] >= date('2019-01-01') and [date] < date('2020-01-01') then price end) avg2019
from mytable
where [date] >= date('2017-01-01') and [date] <= date('2020-01-01)
group by city
I would recommend using date intervals instead of using year()
to define the year each date belongs to, since this will benefit an existing index on date
(while function year()
will not).
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.