Your request seems very simple, but it has two complications. The first is that one row is a summary of the other two. This suggests using rollup
or grouping sets
in the query.
The second is the requirement to have values even when you have no data. This suggests the use of a "driver" subquery. Such a subquery defines all the rows in the output before assigning values. You use a driver table with left outer join
.
An unstated requirement might be to only mention the year once.
The following approach to the query puts the final form together for the year. The then left joins the summary, pulling values from there if any:
with year as (
select 2013 as Year
)
select driver.label, coalesce(s.value, 0) as Value, driver.Year
from ((select 'Male' as label, year from year
) union all
(select 'Female' as label, year from year
) union all
(select 'Total' as label, year from year
)
) driver left outer join
(select coalesce(Gender, 'Total') as Gender, year.year, count(*) as value
from Students cross join year
group by Gender with Rollup
) s
on driver.year = s.year;
This assumes that gender is represented as "Male" and "Female" and that there is a column called year
in the data (without sample input or table formats one has to guess on column names and sample values).