Как считать или суммировать различные значения, когда существует риск пересечения? - PullRequest
1 голос
/ 06 марта 2020

Представьте, что у меня есть таблица с людьми и их функциями:

group    Name  red_hair tall blue_eyes programmer
1         Mark  1        1    0         1
1         Sean  1        0    1         0
1        Lucas  1        1    1         1
2        Linda  0        1    1         1

Я бы хотел посчитать, сколько людей с определенными c наборами функций в каждой группе. Другими словами, я хотел бы сделать несколько корзин, не считая человека несколько раз.

Есть 2 ^ 4 (16) возможных комбинаций этих наборов, но мне не нужно так много.

Например, если у человека есть рыжие волосы, мне все равно, будет ли он или у нее голубые глаза или он или она программист. Этот человек идет в корзину для красных волос этой группы. Если человек программист, мне все равно, высокий ли он или она, но я не хочу считать людей, которые уже в красном бункере для волос. Потому что я их уже посчитал.

Итак, у меня есть приоритет:

  • Красные волосы люди считают первыми
  • Программисты вторые
  • Люди с голубыми глазами третьи

Ожидаемый результат этого набора данных:

group red_hair_persons programmers blue_eyes_persons 
1     3                0           0
2     0                1           0

, когда я сделаю это:

select group, count(case when red_hair = 1 then name end) as red_hair,
count(case when programmer = 1 and red_hair = 0 then name end) as programmers
from table
group by group

Боюсь, что будут некоторые пересечения. Или логика c с CASES была бы настолько сложной, что я мог бы утонуть в ней. Я прав? Если так, как я мог избежать их? Может быть, я делаю все неправильно, и есть лучший способ сделать то, что я хочу. У меня огромный стол со множеством функций, и я не хочу облажаться.

Ответы [ 2 ]

1 голос
/ 06 марта 2020

С условной агрегацией немного математики:

select "group",
  sum("red_hair") red_hair_persons,
  sum((1 - "red_hair") * "programmer") programmers,
  sum((1 - "red_hair") * (1 - "programmer") * "blue_eyes") blue_eyes_persons
from tablename
group by "group"

См. demo . Результаты:

> group | RED_HAIR_PERSONS | PROGRAMMERS | BLUE_EYES_PERSONS
> ----: | ---------------: | ----------: | ----------------:
>     1 |                3 |           0 |                 0
>     2 |                0 |           1 |                 0
1 голос
/ 06 марта 2020

Вот как я это понял:

SQL> with test (cgroup, name, red_hair, tall, blue_eyes, programmer) as
  2    (select 1, 'mark' , 1, 1, 0, 1 from dual union all
  3     select 1, 'sean' , 1, 0, 1, 0 from dual union all
  4     select 1, 'lucas', 1, 1, 1, 1 from dual union all
  5     select 2, 'linda', 0, 1, 1, 1 from dual
  6    ),
  7  priority as
  8    (select t.*,
  9       case when red_hair   = 1 then 'A'
 10            when programmer = 1 then 'B'
 11            when blue_eyes  = 1 then 'C'
 12            else 'D'
 13       end priority
 14     from test t
 15    )
 16  select cgroup,
 17    sum(case when priority = 'A' then 1 else 0 end) red_hair,
 18    sum(case when priority = 'B' then 1 else 0 end) programmer,
 19    sum(case when priority = 'C' then 1 else 0 end) blue_eyes,
 20    sum(case when priority = 'D' then 1 else 0 end) other
 21  from priority
 22  group by cgroup;

    CGROUP   RED_HAIR PROGRAMMER  BLUE_EYES      OTHER
---------- ---------- ---------- ---------- ----------
         1          3          0          0          0
         2          0          1          0          0

SQL>
  • priority CTE помещает каждого человека в свою приоритетную группу, основываясь на его свойствах
  • окончательный счетчик выбора (с использованием SUM + CASE) их на группу
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...