SQL独特的组合

时间:2017-06-28 20:02:07

标签: sql oracle string-aggregation

我有一个包含三个列的表,一个ID,一个治疗类,然后是一个通用名称。治疗类可以映射到多个通用名称。

ID     therapeutic_class       generic_name
1           YG4                    insulin
1           CJ6                    maleate
1           MG9                    glargine
2           C4C                    diaoxy
2           KR3                    supplies
3           YG4                    insuilin
3           CJ6                    maleate
3           MG9                    glargine

我需要首先查看治疗类和通用名称的各个组合,然后想要计算有多少患者具有相同的组合。我希望我的输出有三列:一个是通用名称的组合,治疗类的组合和组合患者数量的计数如下:

Count          Combination_generic                   combination_therapeutic
2              insulin, maleate, glargine                 YG4, CJ6, MG9
1              supplies, diaoxy                           C4C, KR3

2 个答案:

答案 0 :(得分:2)

通过成对对(therapeutic_class, generic_name)匹配患者的一种方法是在所需的输出中创建逗号分隔的字符串,并按它们分组并计数。要做到这一点,您需要一种方法来识别对。请参阅原始问题下的评论和我对Gordon的答案,以了解其中的一些问题。

我在以下解决方案的一些初步工作中进行了识别。正如我在评论中提到的,如果您的数据模型中已存在配对和唯一ID,那就更好了;我动态创建它们。

重要提示:这假设以逗号分隔的列表不会太长。如果超过4000个字符(或Oracle 12中的大约32000个字符,并且某些选项已打开),您可以将字符串聚合到CLOB中,但是您可以使用GROUP BY个CLOB(通常,不仅仅是这种情况),所以这种方法将失败。更健壮的方法是匹配对的集合,而不是它们的一些集合。解决方案更复杂,除非您的问题需要,否则我不会介绍它。

with
         -- Begin simulated data (not part of the solution)
         test_data ( id, therapeutic_class, generic_name ) as (
           select 1, 'GY6', 'insulin'  from dual union all
           select 1, 'MH4', 'maleate'  from dual union all
           select 1, 'KJ*', 'glargine' from dual union all
           select 2, 'GY6', 'supplies' from dual union all
           select 2, 'C4C', 'diaoxy'   from dual union all
           select 3, 'GY6', 'insulin'  from dual union all
           select 3, 'MH4', 'maleate'  from dual union all
           select 3, 'KJ*', 'glargine' from dual
         ),
         -- End of simulated data (for testing purposes only).
         -- SQL query solution continues BELOW THIS LINE
     valid_pairs ( pair_id, therapeutic_class, generic_name ) as (
       select rownum, therapeutic_class, generic_name
       from   (
                select distinct therapeutic_class, generic_name
                from   test_data
              )
     ),
     first_agg ( id, tc_list, gn_list ) as (
       select t.id, 
              listagg(p.therapeutic_class, ',') within group (order by p.pair_id),
              listagg(p.generic_name     , ',') within group (order by p.pair_id)
       from   test_data t join valid_pairs p
                           on t.therapeutic_class = p.therapeutic_class
                          and t.generic_name      = p.generic_name
       group by t.id
     )
select   count(*) as cnt, tc_list, gn_list
from     first_agg
group by tc_list, gn_list
;

<强>输出

CNT TC_LIST            GN_LIST                      
--- ------------------ ------------------------------
  1 GY6,C4C            supplies,diaoxy               
  2 GY6,KJ*,MH4        insulin,glargine,maleate     

答案 1 :(得分:1)

您正在寻找listagg(),然后是另一个聚合。我想:

select therapeutics, generics, count(*)
from (select id, listagg(therapeutic_class, ', ') within group (order by therapeutic_class) as therapeutics,
             listagg(generic_name, ', ') within group (order by generic_name) as generics
      from t
      group by id
     ) t
group by therapeutics, generics;