【问题标题】:Using case, count, and group by in 1 query在 1 个查询中使用 case、count 和 group by
【发布时间】:2018-04-13 10:42:13
【问题描述】:

我需要加入 3 个表,对数据进行计数/求和并对数据进行分组。下面是我的表格的非常简化的版本。

    People p
ID 
1
2
3
    Accounts a
ID | Balance | PeopleFK
1  | 50      | 1
2  | 25      | 2
3  | 15      | 3

    Cards c
ID | Status | PeopleFK
1  | Active | 1
2  | Inact  | 1
3  | Active | 2
4  | Other  | 2

到目前为止我所拥有的:

select sum(a.balance),count(c.*),
case when c.status='Active' then 'Active'
case when c.status IN ('Inactive','Other') then 'Inact'
case when c.status is null then 'No Card' end as 'CardStatus'
from people p
join accounts a on p.id=a.PeopleFK
left join cards c on p.id=c.PeopleFK
group by c.status

所需的结果类似于:

Balance  |  CardStatus  |  CardCount
50       |  Active      |  2
25       | Inactive     |  1
0        | NoCard       |  1

但我的结果按所有卡片状态分组。我理解为什么会发生这种情况,但我不确定如何在不为每种情况编写单独的查询的情况下解决这个问题。

因此,它们不是将 Inactive 和 Other 组合在一起,而是组合在一起。

我还在玩这个,但有什么建议吗?

【问题讨论】:

  • 您的Accounts 表缺少数据。请问可以加进去吗?

标签: sql sql-server tsql


【解决方案1】:

使用Group By 时,SELECT 语句只能包含 Group By 语句或聚合函数(如 SUM 或 COUNT)中的字段。

您可以使用 a Common Table Expression (CTE) 将构建 CardStatus 的逻辑整合到一个 select 语句中,然后将其汇集到一个新查询中,该查询在 group by 和 select 语句中都利用它

;WITH BalanceCards AS (
    SELECT a.balance,
           (CASE WHEN c.status='Active'                THEN 'Active'
                 WHEN c.status IN ('Inactive','Other') THEN 'Inact'
                 WHEN c.status IS NULL                 THEN 'No Card' 
            END) AS CardStatus
    FROM people p
    JOIN accounts a ON p.id = a.PeopleFK
    LEFT JOIN cards c ON p.id = c.PeopleFK
)
SELECT bs.CardStatus, 
       SUM(bs.balance) As Total, 
       COUNT(*) As [Count]
FROM BalanceCards bs
GROUP BY bs.CardStatus

【讨论】:

  • 这正是我要找的东西!唯一的问题是我还需要它来返回人员表中拥有帐户但没有卡的任何人。这就是“当 c.status 为 NULL 时”的用途,但我认为这可能行不通,但似乎没有。有什么想法吗?
  • 不确定您的数据是什么样的,但看起来它应该通过LEFT JOIN 执行您想要的操作,并且如果没有用于一个特定的人,但在聚合之前尝试自己运行子查询以证实数据看起来像它自己
  • 你是对的——这是数据,而不是查询。再次感谢!
【解决方案2】:

我相信这是您想要的查询:

select (case when c.status = 'Active' then 'Active'
             when c.status in ('Inactive','Other') then 'Inact'
             when c.status is null then 'No Card'
        end) as CardStatus,
       count(c.PeopleFK) as CardCount, sum(a.balance) as balance
from people p join
     accounts a
     on p.id = a.PeopleFK left join
     cards c
     on p.id = c.PeopleFK
group by (case when c.status = 'Active' then 'Active'
               when c.status in ('Inactive', 'Other') then 'Inact'
               when c.status is null then 'No Card'
          end);

注意事项:

  • 您需要一个 case 表达式来计算状态。
  • 需要在GROUP BY中重复。
  • 不要对列别名使用单引号。仅对字符串和日期常量使用单引号。
  • count(c.*) 在 SQL Server 中无效。

【讨论】:

  • 我使用 CTE 选择了另一个答案,并没有尝试过你的建议,但我相信这也会得到我想要的结果。
猜你喜欢
  • 1970-01-01
  • 2021-12-22
  • 1970-01-01
  • 2021-12-19
  • 2023-03-11
  • 2020-08-15
  • 1970-01-01
  • 1970-01-01
  • 2017-02-24
相关资源
最近更新 更多