使用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;