【问题标题】:Ranking different combinations in SQL在 SQL 中对不同组合进行排序
【发布时间】:2019-10-16 13:37:24
【问题描述】:

我正在处理药房数据,并试图在一大群患者中对三种特定药物(A、B、C)的使用情况进行排名。简而言之,我想找出人们使用的这些药物的前 12 种组合。因此,例如,患者 1 可能服用 A + B 药物,
患者 2 服用 A + C,患者 3 服用 B + C,患者 4 服用 A + B,依此类推。我做了一些挖掘,有 25 种可能的组合进行排名。我希望我的输出看起来像这样:

我正在使用的表如下所示:

目前我正在通过以下方式将药物分成不同的组合组:

select distinct concat(substance_name, dosage, unit) as Drug_Dose_Combo,
count(distinct user_id) as Patients 
from pharmacy_data a join drug_reference_table b 
on a.drug_code=b.drug_code 
group by 1 
order by 2 desc

但是,这似乎非常低效,因此我正在寻找一种更好的方法来构建它。我不一定需要在这里使用 rank(),我只是希望输出看起来类似于我上面概述的内容。

【问题讨论】:

  • 您想要的输出中列出了哪些组,它们与药房和药物参考表有何关联?
  • 后端是什么数据库? Apache-zeppelin 是一个与数据库无关的前端,但可能的解决方案可能取决于后端支持的功能。
  • 所需输出表中的“组”列将是药物的不同组合。简而言之,药物A可以有几种不同的剂量(例如A1、A2、A3),​​药物B可以有几种不同的剂量(例如B1、B2、B3),药物C也可以。因此,患者计数是服用 A1+B1 +C1,或 A2 +B1+C1 或 A3+B2+C1,依此类推。 user total 将是使用每个组合的 user_id 值的总数。这些药物组合将从药房表中获取,使用列 drug_codesubstance_namedosageunit

标签: sql apache-zeppelin


【解决方案1】:

可能类似于(未测试):

WITH meds_taken AS
  (SELECT sum(CASE WHEN d.drug_name = :namea THEN 1 ELSE 0 END) AS drug_a
        , sum(CASE WHEN d.drug_name = :nameb THEN 1 ELSE 0 END) AS drug_b
        , sum(CASE WHEN d.drug_name = :namec THEN 1 ELSE 0 END) AS drug_c
   FROM pharmacy_data AS p
   JOIN drug_reference AS d ON p.drug_code = d.drug_code
   GROUP BY p.user_id)
, med_counts AS
  (SELECT drug_a, drug_b, drug_c, count(*) AS "user total"
   FROM meds_taken
   GROUP BY drug_a, drug_b, drug_c)
SELECT rank() OVER (ORDER BY "user total" DESC) AS rank
     , drug_a, drug_b, drug_c, "user total"
FROM med_counts
ORDER BY "user total" DESC;

【讨论】:

    【解决方案2】:

    好吧,不太清楚您要查找的内容,但您确实表明您希望根据最多三种药品的组合执行某种频率分析。

    此类分析的第一步是获取药房数据,并为每个 user_id 确定他们参与的 1、2 和 3 个 drug_dose 组合的集合,因为您可能想要这样做对substance_namedrug_name 和/或drug_code 进行相同的分析,我将把厨房水槽扔给它,然后全部四个。不知道您在后端拥有哪种类型的数据库,我将在此示例中使用 SQL Server 2017,尽管使用的概念适用于 Oracle、MySQL、PostgreSQL 等数据库,尽管语法可能有所不同。

    要创建drug_code 和其他组合,我将首先将pharmacy_data 表连接到drug_reference 表,然后对复合数据使用递归查询:

    with usage_info as (
      select pd.user_id
           , dr.drug_code
           , dr.drug_name
           , dr.substance_name
           , concat(dr.substance_name,dr.dosage,dr.unit) drug_dose
        from pharmacy_data pd
        join drug_reference dr
          on dr.drug_code = pd.drug_code
    ), recur(user_id, combo_id, dc_combo, dc_combo_size, dn_combo, sn_combo, dd_combo, last_dc) as (
      -- Anchor part
      select user_id
           , cast(cast(drug_code as binary(4)) as varbinary(max))
           , cast(drug_code as varchar(max))
           , 1
           , cast(drug_name as varchar(max))
           , cast(substance_name as varchar(max))
           , cast(drug_dose as varchar(max))
           , drug_code
        from usage_info
    
      union all
      -- Recursive Part
      select prev.user_id
           , prev.combo_id+cast(curr.drug_code as binary(4))
           , prev.dc_combo+','+cast(curr.drug_code as varchar(max))
           , prev.dc_combo_size+1
           , prev.dn_combo+','+curr.drug_name
           , prev.sn_combo+','+curr.substance_name
           , prev.dd_combo+','+curr.drug_dose
           , curr.drug_code
        from recur prev
        join usage_info curr
          on prev.user_id = curr.user_id
         and prev.last_dc < curr.drug_code
         and prev.dc_combo_size < 3 -- Maximum combination size
    )
    

    从上述公用表表达式中选择您问题中提供的数据:

    select * from recur;
    

    显示dn_combosn_combo 和可能的dd_combo 列的分组中存在一些违规行为,例如,'CAZERTA,BEXERA' 和 'BEXERA,CAZERTA' 都存在dn_combos,这确实应该等价

    为了纠正这个问题,我将通过拆分组合并按排序顺序重新组合来规范化组合。在此过程中,我还将对 user_id 可能具有两个或多个等效但不相同的产品的任何实例进行重复数据删除,例如两种不同剂量的同一种药物:

    , combos as (
    select user_id
         , combo_id
         , dc_combo
         , dc_combo_size
         , -- Normalize and deduplicate Drug_Name combos
           (select string_agg(value,',') within group (order by value)
              from (select distinct value from string_split(dn_combo,',')) dn
           ) dn_combo
         , (select count(distinct value) from string_split(dn_combo,',')) dn_combo_size
         , -- Normalize and deduplicate Substance_Name combos
           (select string_agg(value,',') within group (order by value)
              from (select distinct value from string_split(sn_combo,',')) sn
           ) sn_combo
         , (select count(distinct value) from string_split(sn_combo,',')) sn_combo_size
         , -- Normalize and deduplicate Drug_Dose combos
           (select string_agg(value,',') within group (order by value)
              from (select distinct value from string_split(dd_combo,',')) ddc
           ) dd_combo
         , (select count(distinct value) from string_split(dd_combo,',')) dd_combo_size
      from recur
    )
    

    现在,虽然您可以选择 count(user_id) over (partition by &lt;grouping_column&gt;) 来获取每种药物组合的出现频率,但这些数字可能会被夸大。例如,如果您的数据有额外的user_id 999 和drug_codes 50、100、200 和 350(这是 BEXERA 以及 AXIOM 和 CAZERTA 的两种不同剂量),那么user_id 999 将显示多个包括 BEXERA 在内的每个组合的时间。根据您的数据库风格,您可以只选择count(DISTINCT user_id) over (partition by &lt;grouping_column&gt;),但从 SQL Server 2017 开始,它不允许在分析函数中使用 distinct 运算符。 &lt;/shrug&gt; 我们仍然可以这样做,只需再采取一步来识别每个组的唯一值。输入 Common Table combo2,我们在其中计算各个分区的行号:

    , combo2 as (
    select user_id
         , combo_id
         , dc_combo
         , dc_combo_size
         , row_number() over (partition by dc_combo, user_id order by dc_combo) dc_uid_rn
         , dn_combo
         , dn_combo_size
         , row_number() over (partition by dn_combo, user_id order by dc_combo) dn_uid_rn
         , row_number() over (partition by dn_combo, dc_combo order by user_id) dn_combo_rn
         , sn_combo
         , sn_combo_size
         , row_number() over (partition by sn_combo, user_id order by dc_combo) sn_uid_rn
         , row_number() over (partition by sn_combo, dc_combo order by user_id) sn_combo_rn
         , dd_combo
         , dd_combo_size
         , row_number() over (partition by dd_combo, user_id order by dc_combo) dd_uid_rn
         , row_number() over (partition by dd_combo, dc_combo order by user_id) dd_combo_rn
      from combos
    )
    

    然后最后计算我们有两种类型的计数。 uid_cnt 列是每个组合的不同 user_ids 的计数,combo_cnt 列表示构成较小粒度分组的不同 drug_code 组合的数量:

    select user_id
         , combo_id
         , dc_combo
         , dc_combo_size
         , count(case dc_uid_rn when 1 then 1 end) over (partition by dc_combo) dc_uid_cnt
         , dn_combo
         , dn_combo_size
         , count(case dn_uid_rn when 1 then 1 end) over (partition by dn_combo) dn_uid_cnt
         , count(case dn_combo_rn when 1 then 1 end) over (partition by dn_combo) dn_combo_cnt
         , sn_combo
         , sn_combo_size
         , count(case sn_uid_rn when 1 then 1 end) over (partition by sn_combo) sn_uid_cnt
         , count(case sn_combo_rn when 1 then 1 end) over (partition by sn_combo) sn_combo_cnt
         , dd_combo
         , dd_combo_size
         , count(case dd_uid_rn when 1 then 1 end) over (partition by dd_combo) dd_uid_cnt
         , count(case dd_combo_rn when 1 then 1 end) over (partition by dd_combo) dd_combo_cnt
      from combo2
      order by dn_combo, dd_combo
    

    上面的代码连同我的其他示例数据导致以下 table。要查看它的实际效果,请查看SQL Fiddle

    | user_id |    dc_combo | dc_combo_size | dc_uid_cnt |             dn_combo | dn_combo_size | dn_uid_cnt | dn_combo_cnt |                        sn_combo | sn_combo_size | sn_uid_cnt | sn_combo_cnt |                                        dd_combo | dd_combo_size | dd_uid_cnt | dd_combo_cnt |
    |---------|-------------|---------------|------------|----------------------|---------------|------------|--------------|---------------------------------|---------------|------------|--------------|-------------------------------------------------|---------------|------------|--------------|
    |       3 |         200 |             1 |          2 |                AXIOM |             1 |          4 |            3 |                           nsaid |             1 |          4 |            3 |                                       nsaid10mg |             1 |          2 |            1 |
    |     999 |         200 |             1 |          2 |                AXIOM |             1 |          4 |            3 |                           nsaid |             1 |          4 |            3 |                                       nsaid10mg |             1 |          2 |            1 |
    |     175 |         300 |             1 |          1 |                AXIOM |             1 |          4 |            3 |                           nsaid |             1 |          4 |            3 |                                       nsaid25mg |             1 |          1 |            1 |
    |       1 |          25 |             1 |          1 |                AXIOM |             1 |          4 |            3 |                           nsaid |             1 |          4 |            3 |                                        nsaid5mg |             1 |          1 |            1 |
    |     999 |     200,350 |             2 |          1 |         AXIOM,BEXERA |             2 |          3 |            5 |                 nsaid,potassium |             2 |          3 |            5 |                         nsaid10mg,potassium12mg |             2 |          1 |            1 |
    |     999 |  50,200,350 |             3 |          1 |         AXIOM,BEXERA |             2 |          3 |            5 |                 nsaid,potassium |             2 |          3 |            5 |           nsaid10mg,potassium12mg,potassium20mg |             3 |          1 |            1 |
    |     999 |      50,200 |             2 |          1 |         AXIOM,BEXERA |             2 |          3 |            5 |                 nsaid,potassium |             2 |          3 |            5 |                         nsaid10mg,potassium20mg |             2 |          1 |            1 |
    |     175 |      50,300 |             2 |          1 |         AXIOM,BEXERA |             2 |          3 |            5 |                 nsaid,potassium |             2 |          3 |            5 |                         nsaid25mg,potassium20mg |             2 |          1 |            1 |
    |       1 |       25,50 |             2 |          1 |         AXIOM,BEXERA |             2 |          3 |            5 |                 nsaid,potassium |             2 |          3 |            5 |                          nsaid5mg,potassium20mg |             2 |          1 |            1 |
    |     999 | 100,200,350 |             3 |          1 | AXIOM,BEXERA,CAZERTA |             3 |          2 |            3 | nsaid,potassium,sodium chloride |             3 |          2 |            3 |     nsaid10mg,potassium12mg,sodium chloride10mg |             3 |          1 |            1 |
    |     999 |  50,100,200 |             3 |          1 | AXIOM,BEXERA,CAZERTA |             3 |          2 |            3 | nsaid,potassium,sodium chloride |             3 |          2 |            3 |     nsaid10mg,potassium20mg,sodium chloride10mg |             3 |          1 |            1 |
    |       1 |   25,50,100 |             3 |          1 | AXIOM,BEXERA,CAZERTA |             3 |          2 |            3 | nsaid,potassium,sodium chloride |             3 |          2 |            3 |      nsaid5mg,potassium20mg,sodium chloride10mg |             3 |          1 |            1 |
    |     999 |     100,200 |             2 |          1 |        AXIOM,CAZERTA |             2 |          2 |            2 |           nsaid,sodium chloride |             2 |          2 |            2 |                   nsaid10mg,sodium chloride10mg |             2 |          1 |            1 |
    |       1 |      25,100 |             2 |          1 |        AXIOM,CAZERTA |             2 |          2 |            2 |           nsaid,sodium chloride |             2 |          2 |            2 |                    nsaid5mg,sodium chloride10mg |             2 |          1 |            1 |
    |     201 |         350 |             1 |          2 |               BEXERA |             1 |          5 |            4 |                       potassium |             1 |          5 |            4 |                                   potassium12mg |             1 |          2 |            1 |
    |     999 |         350 |             1 |          2 |               BEXERA |             1 |          5 |            4 |                       potassium |             1 |          5 |            4 |                                   potassium12mg |             1 |          2 |            1 |
    |     999 |      50,350 |             2 |          1 |               BEXERA |             1 |          5 |            4 |                       potassium |             1 |          5 |            4 |                     potassium12mg,potassium20mg |             2 |          1 |            1 |
    |     378 |         400 |             1 |          1 |               BEXERA |             1 |          5 |            4 |                       potassium |             1 |          5 |            4 |                                   potassium15mg |             1 |          1 |            1 |
    |       1 |          50 |             1 |          3 |               BEXERA |             1 |          5 |            4 |                       potassium |             1 |          5 |            4 |                                   potassium20mg |             1 |          3 |            1 |
    |     175 |          50 |             1 |          3 |               BEXERA |             1 |          5 |            4 |                       potassium |             1 |          5 |            4 |                                   potassium20mg |             1 |          3 |            1 |
    |     999 |          50 |             1 |          3 |               BEXERA |             1 |          5 |            4 |                       potassium |             1 |          5 |            4 |                                   potassium20mg |             1 |          3 |            1 |
    |     999 |  50,100,350 |             3 |          1 |       BEXERA,CAZERTA |             2 |          4 |            5 |       potassium,sodium chloride |             2 |          4 |            5 | potassium12mg,potassium20mg,sodium chloride10mg |             3 |          1 |            1 |
    |     999 |     100,350 |             2 |          1 |       BEXERA,CAZERTA |             2 |          4 |            5 |       potassium,sodium chloride |             2 |          4 |            5 |               potassium12mg,sodium chloride10mg |             2 |          1 |            1 |
    |     201 |     350,450 |             2 |          1 |       BEXERA,CAZERTA |             2 |          4 |            5 |       potassium,sodium chloride |             2 |          4 |            5 |               potassium12mg,sodium chloride30mg |             2 |          1 |            1 |
    |     378 |     100,400 |             2 |          1 |       BEXERA,CAZERTA |             2 |          4 |            5 |       potassium,sodium chloride |             2 |          4 |            5 |               potassium15mg,sodium chloride10mg |             2 |          1 |            1 |
    |       1 |      50,100 |             2 |          2 |       BEXERA,CAZERTA |             2 |          4 |            5 |       potassium,sodium chloride |             2 |          4 |            5 |               potassium20mg,sodium chloride10mg |             2 |          2 |            1 |
    |     999 |      50,100 |             2 |          2 |       BEXERA,CAZERTA |             2 |          4 |            5 |       potassium,sodium chloride |             2 |          4 |            5 |               potassium20mg,sodium chloride10mg |             2 |          2 |            1 |
    |       1 |         100 |             1 |          3 |              CAZERTA |             1 |          4 |            2 |                 sodium chloride |             1 |          4 |            2 |                             sodium chloride10mg |             1 |          3 |            1 |
    |     378 |         100 |             1 |          3 |              CAZERTA |             1 |          4 |            2 |                 sodium chloride |             1 |          4 |            2 |                             sodium chloride10mg |             1 |          3 |            1 |
    |     999 |         100 |             1 |          3 |              CAZERTA |             1 |          4 |            2 |                 sodium chloride |             1 |          4 |            2 |                             sodium chloride10mg |             1 |          3 |            1 |
    |     201 |         450 |             1 |          1 |              CAZERTA |             1 |          4 |            2 |                 sodium chloride |             1 |          4 |            2 |                             sodium chloride30mg |             1 |          1 |            1 |
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-04-12
      • 1970-01-01
      • 2013-09-03
      • 2023-02-24
      • 2011-12-30
      • 2017-08-16
      • 2018-04-10
      • 1970-01-01
      相关资源
      最近更新 更多