【问题标题】:SQL getting counts for several rows grouped by a columnSQL 获取按列分组的几行的计数
【发布时间】:2019-08-11 14:20:58
【问题描述】:

我正在尝试为每列计算多个单独的行。下面是我想要完成的一个示例。

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

当我运行它时,它会将每一行的所有记录汇总在一起,而不仅仅是该章的记录。有什么建议吗?

输出示例

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

我真正想要的是

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

【问题讨论】:

  • 你需要条件聚合,其中COUNTSUM(CASE WHEN ... THEN 1 ELSE 0)模拟
  • “为每列计算多个单独的行”不清楚。使用足够多的单词、句子和对部分示例的引用来清楚完整地表达你的意思。说得足够多,有人可以离开并带着解决方案回来。请在代码问题中给出minimal reproducible example--cut & paste & runnable code 加上所需的输出加上清晰的规范和解释。最小意味着将最少的问题代码添加到最少的工作代码中。因此,给出你所展示的最少代码,并在你出错的第一个地方提供最少的代码。 (调试基础。)

标签: sql sql-server join select


【解决方案1】:

考虑将所有子查询替换为计算列,第一个 name 只是作为主表的 JOIN。对于计数,通过对条件求和来使用条件聚合。此外,调整 GROUP BY 以包含 name 而不是唯一 ID,这可能是重复数据的原因。此外,请检查 WHERE 中的术语日期范围,因为它们似乎是多余的。

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

【讨论】:

    【解决方案2】:

    条件聚合应该做你想做的事。在 SQL Server 中,我将其表述为:

    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;
    

    请注意,这也限定了所有列名并简化了日期运算。

    【讨论】:

      【解决方案3】:

      请试试这个:

      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
      ;
      

      【讨论】:

        猜你喜欢
        • 2019-04-22
        • 2018-11-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-03-08
        • 2022-01-19
        相关资源
        最近更新 更多