有效的方法来提取字段的所有排列的计数

时间:2017-05-03 14:28:08

标签: sql oracle

我有一个oracle DB w /表包含与人关联的记录(基于ID)。记录分类为类别= 1,2或3。

我想说如下:
- 只有1类记录(没有类别= 2或3)的人数# - 只有2类记录(没有类别= 1或3)的人数# - 只有3类记录(没有类别= 1或2)的人数# - 同时拥有1类和1类人员的人数2条记录(无类别= 3)
- 同时拥有1类和1类人员的人数3条记录(无类别= 2)
- 所有类别记录的人数#1,2和& 3
- 同时拥有2类和2类的人数3条记录(无类别= 1)

我只能想到以下解决方案(针对每种情况进行了修改):

select count(*) from table1
where id in (select id from table1 where category=1)
and id not in (select id from table1 where category=2)
and id not in (select id from table1 where category=3)

但是,我相信这是一种非常低效的方式,我想知道是否有人有更快/更好的方式来获取这些信息。

谢谢!

3 个答案:

答案 0 :(得分:1)

执行此操作的一种方法是使用listagg()将类别组合在一起,然后重新聚合:

select categories, count(*)
from (select listagg(t1.category, ',') within group (order by t1.category) as categories, personid
      from table1 t1
      group by personid
     ) x
group by categories;

编辑:

如果您需要不同的值:

select categories, count(*)
from (select listagg(t1.category, ',') within group (order by t1.category) as categories, personid
      from (select distinct t1.category, t1.personid from table1 t1) t1
      group by personid
     ) x
group by categories;

答案 1 :(得分:0)

这是一个查询,对于每个ID,显示不同类别的计数以及MIN和MAX类别。此查询可用作进一步处理中的子查询(您没有准确解释您希望如何呈现结果)。当COUNT为1时,单个类别是MIN_CAT列中的类别;当COUNT为3时,则该ID的所有三个类别都存在;当COUNT为2时,则存在的两个类别在MIN和MAX列中。无论你需要做什么,都应该非常简单;例如,您现在可以进行GROUP BY CT,MIN_CAT,MAX_CT和计数ID。

我做一个计数(不同类别)以允许非唯一(id, category)的可能性 - 如我在WITH子句中包含的示例数据中所示(这不是SQL查询的一部分!)

with
     test_data ( id, category ) as (
       select 101, 3 from dual union all
       select 101, 1 from dual union all
       select 101, 3 from dual union all
       select 104, 2 from dual union all
       select 105, 2 from dual union all
       select 105, 2 from dual union all
       select 105, 1 from dual union all
       select 106, 1 from dual union all
       select 106, 2 from dual union all
       select 106, 3 from dual union all
       select 106, 3 from dual
     )
select   id,
         count(distinct category) as ct,
         min(category)            as min_cat,
         max(category)            as max_cat
from     test_data
group by id
;

ID   CT  MIN_CAT  MAX_CAT
---  --  -------  -------
101   2        1        3
105   2        1        2
104   1        2        2
106   3        1        3

答案 2 :(得分:0)

Oracle安装程序

CREATE TABLE test_data ( id, category ) as
 select 101, 3 from dual union all
 select 101, 1 from dual union all
 select 101, 3 from dual union all
 select 104, 2 from dual union all
 select 105, 2 from dual union all
 select 105, 2 from dual union all
 select 105, 1 from dual union all
 select 106, 1 from dual union all
 select 106, 2 from dual union all
 select 106, 3 from dual union all
 select 106, 3 from dual union all
 select 107, 1 from dual union all
 select 107, 3 from dual;

<强>查询

SELECT c1,
       c2,
       c3,
       LTRIM(
         DECODE( c1, 1, ',1' ) || DECODE( c2, 1, ',2' ) || DECODE( c3, 1, ',3' ),
         ','
       ) AS categories,
       COUNT(1) AS num_people,
       LISTAGG( id, ',' ) WITHIN GROUP ( ORDER BY id ) AS people
FROM   ( SELECT DISTINCT * FROM test_data )
PIVOT  ( COUNT(1) FOR category IN ( 1 AS c1, 2 AS c2, 3 AS c3 ) )
GROUP BY c1, c2, c3;

<强>输出

C1 C2 C3 CATEGORIES NUM_PEOPLE PEOPLE   
-- -- -- ---------- ---------- ----------
 0  1  0 2                   1 104       
 1  0  1 1,3                 2 101,107   
 1  1  0 1,2                 1 105       
 1  1  1 1,2,3               1 106