Отличительный условный подсчет, чтобы избежать наложения - PullRequest
1 голос
/ 06 февраля 2020

Рассмотрим эту таблицу:

[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, чтобы получить число людей, помеченных Yes и No. Однако, если у кого-то есть один экземпляр No, он должен учитываться как No и не включаться в счет Yes независимо от того, сколько у него 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 в счетах Yes и No.

Мой желаемый результат будет:

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

Я надеюсь избежать снижения производительности от необходимости оценивать подзапрос для каждой строки, но если это будет путь к go, я приму это.

Ответы [ 5 ]

3 голосов
/ 06 февраля 2020

Агрегируйте сначала на уровне человека, а затем в целом:

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
1 голос
/ 06 февраля 2020

Вы можете сначала сгруппировать их по человеку.
Тогда CASE для Yes людей может иметь условие не 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
1 голос
/ 06 февраля 2020

Условное агрегирование можно использовать следующим образом:

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>

Cheers !!

1 голос
/ 06 февраля 2020

Думаю, вам нужно предварительно проверить каждого человека с помощью оконной функции

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;
1 голос
/ 06 февраля 2020

Вы можете использовать оконную функцию для ранжирования строк для единственного person_id, чтобы установить приоритет «Нет» над «Да», но для этого потребуется подзапрос

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

Внутренний подзапрос плюс * Фильтр 1004 * выдаст вам по одной строке на person_id, отдавая приоритет записям «нет».

Это, конечно, предполагает, что да / нет взаимоисключающие, и если это правда, вам, вероятно, следует изменить модель на одно поле.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...