简体   繁体   中英

SQL getting counts for several rows grouped by a column

I am trying to count multiple individual rows for each column. Below is an example of what I am trying to accomplish.

select (select top 1 name
          from chap
         where chap.chp_id = CHS.chp_id) as Chap,
       (select count(*)
          from CHS,
               chap 
         where O_TYPE = 'PRESIDENT'
           and chs.chp_id = chap.chp_id) as Presidents,
       (select count(*)
          from CHS 
         where O_TYPE = 'VICEPRESIDENT') as VicePresidents,
       (select count(*)
          from CHS 
         where OFFICER_TYPE = 'CORRSECRETARY') as CorrespondinSecretaries,
       (select count(*)
          from CHS 
         where O_TYPE = 'RECORDINGSECRETARY') as RecordingSecretaries,
       (select count(*)
          from CHS 
         where O_TYPE = 'TREASURER') as Treasurers,
       (select count(*)
          from CHS 
         where O_TYPE = 'ADVISOR'
           and ADV_CODE = 'B') as ChiefAdvisors,
       (select count(*)
          from CHS 
         where O_TYPE = 'ADVISOR'
           and ADV_CODE <> 'B') as ChiefAdvisors
from CHS
where O_TYPE in ('PRESIDENT', 'VICEPRESIDENT', 'CORRSECRETARY', 'RECORDINGSECRETARY', 'TREASURER', 'ADVISOR')
  and Term_expire >= DateAdd(Day,DateDiff(Day,0,GetDate()),0)
  and Term_Begin <= DateAdd(Day,DateDiff(Day,0,GetDate()),0)
  and CHS.CHP_ID in (Select chp_id 
                            from chrs
                           where active = 'Y') 
Group by chs.CHP_ID

when I run this it totals each row with all of the records not just the records for that chapter. Any suggestions?

Output Example

AL A    247 264 247 250 246 235 739
AL B    247 264 247 250 246 235 739
AL G    247 264 247 250 246 235 739
AL D    247 264 247 250 246 235 739
AK A    247 264 247 250 246 235 739
AZ A    247 264 247 250 246 235 739
AZ B    247 264 247 250 246 235 739
AZ G    247 264 247 250 246 235 739

What I really want is

AL A 1 1 1 4 8 9 16
AL B 1 1 5 7 8 9 21

Consider replacing all subqueries as calculated columns with first name simply being a JOIN to main table. For counts use conditional aggregation by summing the conditions. Additionally, adjust the GROUP BY to include name and not unique id which may be reason for repetitious data. Also, check term date ranges in WHERE as they appear to be redundant.

SELECT chap.name AS Chap,
       SUM(O_TYPE = 'PRESIDENT') AS Presidents,
       SUM(O_TYPE = 'VICEPRESIDENT') AS VicePresidents,
       SUM(OFFICER_TYPE = 'CORRSECRETARY') AS CorrespondingSecretaries,
       SUM(O_TYPE = 'RECORDINGSECRETARY') AS RecordingSecretaries,
       SUM(O_TYPE = 'TREASURER') AS Treasurers,
       SUM(O_TYPE = 'ADVISOR' AND ADV_CODE = 'B') AS ChiefAdvisors,
       SUM(O_TYPE = 'ADVISOR' AND ADV_CODE <> 'B') AS OtherAdvisors

FROM chap
INNER JOIN CHS ON chap.chp_id = CHS.chp_id
INNER JOIN chrs ON CHS.CHP_ID = chrs.CHP_ID AND active = 'Y'
WHERE O_TYPE IN ('PRESIDENT', 'VICEPRESIDENT', 'CORRSECRETARY', 
                 'RECORDINGSECRETARY', 'TREASURER', 'ADVISOR')
  AND Term_expire >= DATEADD(Day, DATEDIFF(Day, 0, GETDATE()), 0)
  AND Term_Begin <= DATEADD(Day, DATEDIFF(Day, 0, GETDATE()), 0)

GROUP BY chap.name

Conditional aggregation should do what you want. In SQL Server, I would phrase this as:

SELECT chap.name AS Chap,
       SUM(CASE WHEN chs.O_TYPE = 'PRESIDENT' THEN 1 ELSE 0 END) AS Presidents,
       SUM(CASE WHEN chs.O_TYPE = 'VICEPRESIDENT' THEN 1 ELSE 0 END) AS VicePresidents,
       SUM(CASE WHEN chs.OFFICER_TYPE = 'CORRSECRETARY' THEN 1 ELSE 0 END) AS CorrespondingSecretaries,
       SUM(CASE WHEN chs.O_TYPE = 'RECORDINGSECRETARY' THEN 1 ELSE 0 END) AS RecordingSecretaries,
       SUM(CASE WHEN chs.O_TYPE = 'TREASURER' THEN 1 ELSE 0 END) AS Treasurers,
       SUM(CASE WHEN chs.O_TYPE = 'ADVISOR' AND ADV_CODE = 'B' THEN 1 ELSE 0 END) AS ChiefAdvisors,
       SUM(CASE WHEN chs.O_TYPE = 'ADVISOR' AND ADV_CODE <> 'B' THEN 1 ELSE 0 END) AS OtherAdvisors
FROM chap JOIN
     CHS
     ON chap.chp_id = CHS.chp_id JOIN
     chrs
     ON CHS.CHP_ID = chrs.CHP_ID AND 
WHERE chrs.active = 'Y' AND
      chap.O_TYPE IN ('PRESIDENT', 'VICEPRESIDENT', 'CORRSECRETARY', 
                      'RECORDINGSECRETARY', 'TREASURER', 'ADVISOR'
                     ) AND
     chap.Term_expire >= CONVERT(DATE, GETDATE()) AND
     chap.Term_Begin <= CONVERT(DATE, GETDATE())
GROUP BY chap.name;

Note that this also qualifies all column names and simplifies the date arithmetic.

Please try this:

SELECT chap.Name AS [Chap]
    ,SUM(IIF(chs.O_TYPE = 'PRESIDENT',1,0)) AS [Presidents]
    ,SUM(IIF(chs.O_TYPE = 'VICEPRESIDENT',1,0)) AS [VicePresidents]
    ,SUM(IIF(chs.O_TYPE = 'CORRSECRETARY',1,0)) AS [CorrespondinSecretaries]
    ,SUM(IIF(chs.O_TYPE = 'RECORDINGSECRETARY',1,0)) AS [RecordingSecretaries]
    ,SUM(IIF(chs.O_TYPE = 'TREASURER',1,0)) AS [Treasurers]
    ,SUM(IIF(chs.O_TYPE = 'ADVISOR' AND chs.ADV_CODE = 'B',1,0)) AS [ChiefAdvisorsB]
    ,SUM(IIF(chs.O_TYPE = 'ADVISOR' AND chs.ADV_CODE <> 'B',1,0)) AS [ChiefAdvisorsNotB]
FROM chs
INNER JOIN chrs ON chrs.CHP_ID = chs.CHP_ID AND chrs.Active = 'Y' /*works as filter*/
INNER JOIN chap ON chap.CHP_ID = chs.CHP_ID
WHERE chs.O_TYPE IN ('PRESIDENT', 'VICEPRESIDENT', 'CORRSECRETARY', 'RECORDINGSECRETARY', 'TREASURER', 'ADVISOR')
    AND DATEADD(DAY,DATEDIFF(DAY,0,GETDATE()),0) BETWEEN chs.Term_Begin AND chs.Term_expire
GROUP BY chap.Name
;

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