简体   繁体   中英

SQL - Dividing by Sum by Group

I am just learning SQL and have run into a problem creating a custom report. I am working with school attendance data. I want to create a report that gives membership days and number of days for each absence type.

I have successfully created a report for these separately.

Membership Days (calculated by counting days school was in session between the student's entry date and the current date. Membership days does not exist as a field on its own)

SELECT sum(case when cd.DATE_VALUE >= s.ENTRYDATE and cd.DATE_VALUE <= current_timestamp THEN cd.INSESSION ELSE 0 END), s.LASTFIRST
FROM CALENDAR_DAY cd,STUDENTS s
WHERE cd.SCHOOLID = 405
GROUP BY s.LASTFIRST

Count per absence type

SELECT s.STUDENT_NUMBER, s.LASTFIRST,SUM(CASE WHEN a.ATTENDANCE_CODEID = 2 THEN 1 ELSE 0 END),SUM(CASE WHEN a.ATTENDANCE_CODEID = 4 THEN 1 ELSE 0 END),SUM(CASE WHEN a.ATTENDANCE_CODEID = 3 THEN 1 ELSE 0 END),SUM(CASE WHEN a.ATTENDANCE_CODEID = 51 THEN 1 ELSE 0 END)
FROM ATTENDANCE a
INNER join STUDENTS s
ON a.STUDENTID = s.ID
WHERE a.att_date between '%param1%'  and  '%param2%'
GROUP BY s.STUDENT_NUMBER, s.LASTFIRST

The problem is that if I try to put these in the same report, the membership days are multiplied by the number of times the student appears in the attendance table due to joining student and attendance. My thought on a solution was to then divide this line

sum(case when cd.DATE_VALUE >= s.ENTRYDATE and cd.DATE_VALUE <= current_timestamp THEN cd.INSESSION ELSE 0 END)

by the number of times the student showed up in the attendance table to counteract the student information existing on every line. I can't figure out how to do that. I don't know much about these types of problems, so hopefully I've just gone off on the wrong track and there is an easy solution. Thanks.

Your problem is a common problem -- trying to summarize along two dimensions at the same time without using a subquery. You want to do this query with two aggregation subqueries. Something like this:

SELECT *
FROM (SELECT sum(case when cd.DATE_VALUE >= s.ENTRYDATE and cd.DATE_VALUE <= current_timestamp 
                     THEN cd.INSESSION
                     ELSE 0
                 END), s. STUDENT_NUMBER
      FROM CALENDAR_DAY cd CROSS JOIN
           STUDENTS s
      WHERE cd.SCHOOLID = 405
      GROUP BY s.STUDENT_NUMBER
     ) sc JOIN
     (SELECT s.STUDENT_NUMBER, s.LASTFIRST,
             SUM(CASE WHEN a.ATTENDANCE_CODEID = 2 THEN 1 ELSE 0 END),
             SUM(CASE WHEN a.ATTENDANCE_CODEID = 4 THEN 1 ELSE 0 END),
             SUM(CASE WHEN a.ATTENDANCE_CODEID = 3 THEN 1 ELSE 0 END),
             SUM(CASE WHEN a.ATTENDANCE_CODEID = 51 THEN 1 ELSE 0 END)
      FROM ATTENDANCE a INNER join
           STUDENTS s
           ON a.STUDENTID = s.ID
      WHERE a.att_date between '%param1%'  and  '%param2%'
      GROUP BY s.STUDENT_NUMBER, s.LASTFIRST
     ) sa
     on sc.STUDENT_NUMBER = sa.STUDENT_NUMBER;

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