【问题标题】:SQL unique combinationsSQL 唯一组合
【发布时间】:2017-06-28 20:02:06
【问题描述】:

我有一个包含三列的表,其中包含一个 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

【问题讨论】:

  • 你在找listagg()
  • Do not post sample data as screen shots 使用格式化文本 - 就像你在开始时所做的那样。
  • 数据模型不太对。您可能有单独的表格用于治疗类别和通用名称(如果不这样做,则应该),但缺少一个。大概不是每个通用名称都可以与每个治疗类别相关联。只有一些对是有效的,而另一些是无效的。这应该在一个单独的、多对多的关联表中,每个有效对都有一个唯一的标识符。然后,您的带有患者和成对(治疗类、通用名称)的表应该有患者和此类有效对的唯一 ID。这也会使查询更简单。

标签: sql oracle string-aggregation


【解决方案1】:

通过(therapeutic_class, generic_name) 对的集合匹配患者的一种方法是在所需的输出中创建逗号分隔的字符串,并按它们分组并计数。要正确执行此操作,您需要一种识别对的方法。请参阅我在原始问题下的评论和我对 Gordon's Answer 的评论以了解其中的一些问题。

我在以下解决方案的一些初步工作中进行了此识别。正如我在评论中提到的,如果数据模型中已经存在对和唯一 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     

【讨论】:

    【解决方案2】:

    您正在寻找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;
    

    【讨论】:

    • 如果两个不同的治疗类别可能映射到相同的两个通用名称,这可能会失败。例如,A 和 B 都可能具有通用名称 x 和 y。然后,使用 ORDER BY 子句,两个具有 (A, x), (B, y) 对和 (A, y), (B, x) 对的患者将被放在@987654323 中的同一组中@.
    • 此外,OP 的所需输出似乎具有与逗号分隔字符串中的治疗类相同的顺序排列的通用名称。这不适用于独立的 ORDER BY 标准。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-08-20
    • 1970-01-01
    • 1970-01-01
    • 2012-04-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多