不同的条件计数以避免重叠

Distinct Conditional Counting to Avoid Overlap

考虑这个 table:

[Table1]
------------------------
| Person_ID | Yes | No |
|-----------|-----|----|
|     1     |  1  | 0  |
|-----------|-----|----|
|     1     |  1  | 0  |
|-----------|-----|----|
|     2     |  0  | 1  |
|-----------|-----|----|
|     2     |  0  | 1  |
|-----------|-----|----|
|     3     |  1  | 0  |
|-----------|-----|----|
|     3     |  1  | 0  |
|-----------|-----|----|
|     3     |  0  | 1  |
|-----------|-----|----|
|     3     |  1  | 0  |
------------------------

我需要对 Person_ID 进行不同的计数,以获得标记为 YesNo 的人数。但是,如果某人有一个 No 实例,则无论他们有多少 Yes,都应将其计为 No,而不应计入 Yes 计数。

我的第一个想法是尝试类似的东西:

select count(distinct (case when Yes = 1 then Person_ID else null end)) Yes_People
     , count(distinct (case when No = 1 then Person_ID else null end)) No_People
from Table1

但这将导致 3 被计入 YesNo 计数。

我想要的输出是:

--------------------------
| Yes_People | No_People |
|------------|-----------|
|      1     |     2     |
--------------------------

我希望避免因必须针对每一行评估子查询而对性能造成影响,但如果必须这样做,我会接受。

您可以使用 window 函数对单个 person_id 的行进行排名,使 'No' 优先于 'Yes',但这需要子查询

select count(case when yes=1 then 1 end) as yes_count, 
 count(case when no=1 then no_count) as no_count
from (
   select person_id, yes, no, row_number() over (order by no desc, yes desc) as rn
   from table1
) 
where rn = 1

内部子查询加上 where 过滤器将为每个 person_id 获取一行,优先考虑 'no' 条记录。

这当然假设 yes/no 是互斥的,如果是这样,您可能应该将模型更改为单个字段。

认为您需要使用 window 功能预先检查每个人

with t as (select 1 p_id, 1 yes, 0 no from dual
   union all select 1 p_id, 1 yes, 0 no from dual
   union all select 2 p_id, 0 yes, 1 no from dual
   union all select 2 p_id, 0 yes, 1 no from dual
   union all select 3 p_id, 1 yes, 0 no from dual
   union all select 3 p_id, 0 yes, 1 no from dual
   union all select 3 p_id, 1 yes, 0 no from dual)
, chk as (
   select max(no) over (partition by p_id)  n
        , max(yes) over (partition by p_id) y
        , p_id
   from   t)
--   select * from chk;
   select count(distinct decode(y-n,1,p_id,null )) yes_people
        , count(distinct decode(n,1,p_id,null )) no_people
   from chk
   group by 1;

先在个人层面汇总,然后再汇总:

select sum(yes_only) as yes_only,
       sum(1 - yes_only) as no
from (select person_id,
             (case when max(yes) = min(yes) and max(yes) = 1
                   then 1
              end) as yes_only
      from t
      group by person_id
     ) t

您可以按如下方式使用条件聚合:

SQL> with table1 as (select 1 PERSON_ID, 1 yes, 0 no from dual
  2     union all select 1 PERSON_ID, 1 yes, 0 no from dual
  3     union all select 2 PERSON_ID, 0 yes, 1 no from dual
  4     union all select 2 PERSON_ID, 0 yes, 1 no from dual
  5     union all select 3 PERSON_ID, 1 yes, 0 no from dual
  6     union all select 3 PERSON_ID, 0 yes, 1 no from dual
  7     union all select 3 PERSON_ID, 1 yes, 0 no from dual)
  8  SELECT
  9      SUM(CASE WHEN NOS = 0 AND YES > 0 THEN 1 END) YES_PEOPLE,
 10      SUM(CASE WHEN NOS > 0 THEN 1 END) NO_PEOPLE
 11  FROM
 12     (
 13      SELECT
 14          SUM(NO) NOS,
 15          PERSON_ID,
 16          SUM(YES) YES
 17      FROM TABLE1
 18     GROUP BY PERSON_ID
 19     );

YES_PEOPLE  NO_PEOPLE
---------- ----------
         1          2

SQL>

干杯!!

你可以先按人物分组。
那么 CASEYes 人可以有一个不是 No 的条件。

SELECT 
 COUNT(CASE WHEN No = 0 AND Yes = 1 THEN Person_ID END) AS Yes_People,
 COUNT(CASE WHEN No = 1 THEN Person_ID END) AS No_People
FROM 
(
     select Person_ID
     , MAX(Yes) as Yes
     , MAX(No) as No
     FROM Table1
     GROUP BY Person_ID
) q