使用CASE在SQL中使用if/else逻辑正确计数项
假设我有一张表格,表格如下:使用CASE在SQL中使用if/else逻辑正确计数项,sql,case,Sql,Case,假设我有一张表格,表格如下: | user | class | |------|-------| | 1 | a | | 1 | b | | 1 | b | | 2 | b | | 3 | a | 只有两门课 我想写一个查询,这样我们可以计算每个类中的用户数量,这样任何有标签a和b的用户都可以被排序到a中,任何只有a的用户都可以被排序到a中,然后任何只有b的用户都可以被排序到b中。如果应用于上面的表片段,我们将得到: | c
| user | class |
|------|-------|
| 1 | a |
| 1 | b |
| 1 | b |
| 2 | b |
| 3 | a |
只有两门课
我想写一个查询,这样我们可以计算每个类中的用户数量,这样任何有标签a和b的用户都可以被排序到a中,任何只有a的用户都可以被排序到a中,然后任何只有b的用户都可以被排序到b中。如果应用于上面的表片段,我们将得到:
| class | count |
|-------|-------|
| a | 2 |
| b | 1 |
转置也是可以接受的,例如:
| a | b |
|---|---|
| 2 | 1 |
我目前的解决方案涉及两个CTE:
WITH a_users AS
(
SELECT
user,
SUM(CASE WHEN class = 'a' THEN 1 ELSE 0 END) AS a_class
FROM
table
WHERE
class in ('a', 'b')
GROUP BY
user
),
labeled_users as (
SELECT
user,
CASE WHEN a_class >=1 then 'a' ELSE 'b' END as label
FROM
a_users
)
SELECT
label,
COUNT(DISTINCT user)
FROM
labeled_users;
有没有一种更有效的方法来解决这个问题,还是有一种更简洁易懂的解决方案?如果a和b真的是你的类,那么类似的方法应该可以奏效。否则,根据需要调整最小/最大值
; with CTE as (
Select user, min(class) as Class
from Labeled_Users
group by user)
Select Class, count(*)
from CTE
group by Class
这里是一个直接的查询,使用子查询和条件聚合完成任务。它应该返回预期结果的第二个版本:
SELECT
SUM(CASE WHEN x.minc <> x.maxc OR x.maxc = 'a' THEN 1 ELSE 0 END) a,
SUM(CASE WHEN x.minc = x.maxc AND x.maxc = 'b' THEN 1 ELSE 0 END) b
FROM (
SELECT user, MAX(class) maxclass, MIN(class) minclass
FROM mytable
GROUP BY user
) x
子查询计算每个用户的最小类和最大类。然后外部查询分别统计用户数:
a:属于两个类或仅属于a类的用户
b:仅属于b类的用户
这是标准的SQL语法,显然可以在大多数RDBMS上使用,即使是那些不支持CTE的RDBMS,例如8.0之前的MySQL版本。基本上,对于一个拥有CTE的用户,您需要一个。子查询是第一种方法:
select sum(case when num_as > 0 then 1 else 0 end) as num_class_a,
sum(case when num_as = 0 then 1 else 0 end) as num_class_b
from (select user, sum(case when class = 'a' then 1 else 0 end) as num_as
from t
group by user
) t;
通过一个小技巧,您可以消除子查询:
select count(distinct case when class = 'a' then user end) as num_as,
count(distinct user) - count(distinct case when class = 'a' then user end) as num_bs
from t;
使用字符串_agg:
a真的是超集吗?i、 e.b中的所有人也都在a中?是的,很好,编辑的问题标题是,我不会假设-假设他们是两个不同的字符串逻辑应该仍然有效,你只需要根据需要选择最小/最大值,你想要的类优先。例如,如果您的类是优先级而不是优先级,那么请使用max而不是min,因为优先级排序低于not priority。嘿!您在num_中忘记了下划线,就像在第一个代码段的第二行一样
with usr_class as(
SELECT DISTINCT usr,
string_agg(txt,':') as all_class
FROM abc
GROUP BY usr
)
select count(usr),
case when POSITION('a' in all_class)>0 THEN 'a'
ELSE 'b'
END AS CLASS
FROM usr_class
GROUP BY case when POSITION('a' in all_class)>0 THEN 'a'
ELSE 'b'
END;