简体   繁体   中英

Grouping rows based on values and inserting into another table

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`

See SQL Fiddle with Demo

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;

Demo

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM