Как сгруппировать строки и получить количество на основе других значений столбцов в Oracle - PullRequest
0 голосов
/ 02 января 2019

У меня есть таблица (с именем 'jobs'), имеющая столбцы 'ID' и 'Type'. Столбец ID может иметь один и тот же идентификатор более одного раза, а столбец типа с двумя значениями: «A» и «B». Я хочу получить количество всех идентификаторов с типом «A», с типом «B» и типом «A» и «B».

Я пробовал приведенный ниже запрос, но он дает счетчик типа «A» и типа «B».

SELECT distinct 
       type,
       COUNT( 1 ) OVER ( PARTITION BY type) AS Count
FROM   jobs

Пример данных:

ID    Type    
1      A    
1      B    
2      A    
2      B    
3      A    
4      A    
5      A    
6      B    
7      B    
8      B    
9      B

Ожидаемый результат:

Count of ID’s having just A as type: 3    
Count of ID’s having just B as type : 4    
Count of ID’s having A and B as type : 2    

Ответы [ 4 ]

0 голосов
/ 02 января 2019

Получите 3 разных счетчика для каждого случая:

select 
  (select count(distinct id) from jobs j
   where ((select max(jobs.type) from jobs where jobs.id = j.id) = 'a')
  ) countera,
  (select count(distinct id) from jobs j
   where ((select min(jobs.type) from jobs  where jobs.id = j.id) = 'b')
  ) counterb,
  (select count(distinct id) from jobs j
   where (
      (select min(jobs.type) from jobs  where jobs.id = j.id) = 'a'
      and
      (select max(jobs.type) from jobs  where jobs.id = j.id) = 'b'
    )) counterab
from dual;

См. Демоверсию

Чтобы получить 1 строку для каждого счетчика:

select 
  'Count of IDs having just A as type :' descr,
  count(distinct id) counter from jobs j
where ((select max(jobs.type) from jobs where jobs.id = j.id) = 'a')
union all
select
  'Count of IDs having just B as type :' descr,
  count(distinct id) from jobs j
where ((select min(jobs.type) counter from jobs  where jobs.id = j.id) = 'b')
union all
select 
  'Count of IDs having A and B as type :' descr,
  count(distinct id) counter from jobs j
where 
  (
    (select min(jobs.type) from jobs  where jobs.id = j.id) = 'a'
    and
    (select max(jobs.type) from jobs  where jobs.id = j.id) = 'b'
  );

См. Демоверсию

0 голосов
/ 02 января 2019

Я бы написал так:

select sum(case when num_As > 0 and num_Bs = 0 then 1 else 0 end) as num_A_only,
       sum(case when num_As = 0 and num_Bs > 0 then 1 else 0 end) as num_B_only,
       sum(case when num_As > 0 and num_Bs > 0 then 1 else 0 end) as num_A_and_B       
from (select id,
             sum(case when type = 'A' then 1 else 0 end) as num_As,
             sum(case when type = 'B' then 1 else 0 end) as num_Bs
      from t
      group by id
     ) t;

Если вы хотите это в отдельных строках:

select (case when num_As > 0 and num_Bs = 0 then 'A_only'
             when num_As = 0 and num_Bs > 0 then 'B_only'
             when num_As > 0 and num_Bs > 0 then 'A_and_B'
        end) as grp,
       count(*)       
from (select id,
             sum(case when type = 'A' then 1 else 0 end) as num_As,
             sum(case when type = 'B' then 1 else 0 end) as num_Bs
      from t
      group by id
     ) t
group by (case when num_As > 0 and num_Bs = 0 then 'A_only'
               when num_As = 0 and num_Bs > 0 then 'B_only'
               when num_As > 0 and num_Bs > 0 then 'A_and_B'
          end);
0 голосов
/ 02 января 2019

На основании данных вашего примера ниже будет работать как ожидалось:

with jobs(id,type) AS
    (
    select 1, 'A' FROM DUAL UNION ALL
    select 1, 'A' FROM DUAL UNION ALL
    select 2, 'A' FROM DUAL UNION ALL
    select 2, 'A' FROM DUAL UNION ALL
    select 2, 'B' FROM DUAL UNION ALL
    select 3, 'A' FROM DUAL UNION ALL
    select 3, 'B' FROM DUAL UNION ALL
    select 4, 'B' FROM DUAL UNION ALL
    select 4, 'B' FROM DUAL UNION ALL
    select 5, 'B' FROM DUAL 
    ) 
    SELECT distinct
            j1.type||j2.type as type,
           COUNT( DISTINCT j1.ID ) OVER ( PARTITION BY j1.type||j2.type) AS Count
    FROM   jobs j1 inner join jobs j2 on j1.id = j2.id and j1.type <= j2.type
0 голосов
/ 02 января 2019

Вы можете попробовать это.

--test data
with jobs(id,type) AS
(
select 1, 'A' FROM DUAL UNION ALL
select 1, 'A' FROM DUAL UNION ALL
select 2, 'A' FROM DUAL UNION ALL
select 2, 'A' FROM DUAL UNION ALL
select 2, 'B' FROM DUAL UNION ALL
select 3, 'A' FROM DUAL UNION ALL
select 3, 'B' FROM DUAL UNION ALL
select 4, 'B' FROM DUAL UNION ALL
select 4, 'B' FROM DUAL UNION ALL
select 5, 'B' FROM DUAL 
) --test data ends
select count(only_a) as "Count of Type A Only",
       count(only_b) as "Count of Type B Only",
       count(both_a_and_b) as "Count of Type A and B both"
FROM
(
SELECT
    ID,
    CASE WHEN MAX(TYPE)  = MIN(TYPE) and MIN(TYPE)  = 'A' THEN 1 END only_a,
    CASE WHEN MAX(TYPE)  = MIN(TYPE) and MIN(TYPE)  = 'B' THEN 1 END only_b,
    CASE WHEN COUNT(DISTINCT TYPE) = 2 THEN 1 END both_a_and_b
FROM jobs
WHERE type in ('A','B')
GROUP BY ID
)s;

Демо

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