I have a table that looks like this
Subject Mark Girls Boys
Math 85 4 6
Math 86 1 3
Math 87 1 9
Math 92 2 9
Math 96 9 4
English 83 4 5
English 87 2 4
English 91 2 3
English 99 4 1
And I would want this data to be inserted into another table that looks like
Subject Range Girls Boys
Math 80-89 6 19
Math 90-99 11 13
English 80-89 6 9
English 90-99 6 4
Assuming there are only two digit scores, what should be my query to accomplish this. I tried a very naive GROUP BY
and IF MARK like 1%
but failed miserably.
You can use a CASE
expression to create the range. If you have more ranges, then you will add them to the CASE
:
select subject,
case
when mark >= 80 and mark <= 89 then '80-89'
when mark >= 90 and mark <= 99 then '90-99'
end `Range`,
sum(girls) Girls,
sum(boys) Boys
from yourtable
group by subject, case
when mark >= 80 and mark <= 89 then '80-89'
when mark >= 90 and mark <= 99 then '90-99'
end
order by subject
See SQL Fiddle with Demo .
If you don't want to repeat the CASE
in the GROUP BY
, then you can use a subquery:
select subject,
`range`,
sum(girls) girls,
sum(boys) boys
from
(
select subject,
case
when mark >= 80 and mark <= 89 then '80-89'
when mark >= 90 and mark <= 99 then '90-99'
end `Range`,
girls,
boys
from yourtable
) src
group by subject, `range`
order by subject
See SQL Fiddle with Demo .
I would suggest that you consider creating a table with the start/end range similar to this:
create table mark_ranges
(
start_range int,
end_range int
);
insert into mark_ranges values
(0, 9),
(10, 19),
(20, 29),
(30, 39),
(40, 49),
(50, 59),
(60, 69),
(70, 79),
(80, 89),
(90, 99);
Once you have created the table, getting the ranges is very easy by joining on the table:
select subject,
`range`,
sum(girls) girls,
sum(boys) boys
from
(
select t.subject,
concat(r.start_range, '-', r.end_range) `range`,
t.girls,
t.boys
from yourtable t
inner join mark_ranges r
on t.mark >= r.start_range
and t.mark <= r.end_range
) src
group by subject, `range`
Here is query which will automatically define Mark ranges and produce required result:
SELECT
Subject,
CONCAT(MarkMin, '-', MarkMax),
(
SELECT SUM(Girls)
FROM yourtable
WHERE Subject = Marks.Subject AND Mark >= MarkMin AND Mark <= MarkMax
) AS Girls,
(
SELECT SUM(Boys)
FROM yourtable
WHERE Subject = Marks.Subject AND Mark >= MarkMin AND Mark <= MarkMax
) AS Boys
FROM
(
SELECT
Subject,
ROUND(TRUNCATE(Mark/10,0),0) * 10 AS MarkMin,
ROUND(TRUNCATE(Mark/10,0),0) * 10 + 9 AS MarkMax
FROM yourtable
GROUP BY Subject, MarkMin
) Marks;
Here is TSQL to achieve your result:
select
Subject,
Range,
Girls = Sum(Girls),
Boys = Sum(Boys)
from (
values('80-89', 80, 89),
('90-99', 90, 99)
) T(Range, MinValue, MaxValue)
left join Data on Data.Mark between T.MinValue and T.MaxValue
group by Subject, Range
Here is an example how to do this. I used SQL Server 2008 You can modify the queries with your exact question but I am giving idea. Please mark answer as Accepted if this solves your issue.
-- sample: marks table
create table marks(sj varchar(200), mark int, girl int, boy int)
-- insert some data
insert into marks values ('eng', 85, 2, 3)
insert into marks values ('eng', 86, 3, 4)
insert into marks values ('eng', 95, 4, 5)
insert into marks values ('eng', 95, 5, 6)
-- check data
select * from marks
-- create range table
create table marks_range(sj varchar(200), range varchar(200), girl int, boy int)
--now enter the ranges one by one
--80-89
insert into marks_range
select sj, '80-89', SUM(girl), SUM (boy) from marks where mark < 90 and mark >= 80
group by sj
--90-99
insert into marks_range
select sj, '90-99', SUM(girl), SUM (boy) from marks where mark < 100 and mark >= 90
group by sj
-- check result
select * from marks_range
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.