【问题标题】:group_concat to segregate overlapping dates and combine namesgroup_concat 分离重叠日期并组合名称
【发布时间】:2020-12-30 10:14:03
【问题描述】:

让我解释一下目前的情况:
表结构和数据概览:
我有一张表,其中包含每种药物的患者 ID、药物名称、情节编号及其开始和结束日期。这是只有一个病人的快照。所以这个病人正在使用 2 种药物 X 和 Y。药物 X 的第一集开始于 2013 年 1 月 22 日,结束于 2013 年 4 月 22 日。同样,由于第二个药物也是药物 X,所以它是第二集。换药时视为新药的首发,以此类推。

PATIENT_ID DRUG EPISODE EPISODE_START EPISODE_END
773 X 1 2013-01-22 00:00:00 2013-04-22 00:00:00
773 X 2 2013-06-02 00:00:00 2014-03-12 00:00:00
773 Y 1 2013-10-28 00:00:00 2014-01-22 00:00:00

要求:
我需要为每位患者制定药物治疗方案。我将解释如何: 如果我们将这些数据绘制在一个时间轴上,我们会得到这样的结果:

现在需要按以下顺序创建方案:

在这种情况下,方案将是在特定时间段内使用的药物的组合。
方案 1:药物 X,日期为 2013-01-22 至 2013-04-22,
方案 2:药物 X,日期为 2013-06-22 至 2013-10-28,
方案 3:药物 X+Y 从日期 2013-10-28 到 2014-01-22,最后
方案 4:药物 X,日期为 2014-01-22 至 2014-03-12。

最后,表格最终会是这样的:

PATIENT_ID DRUG_TAKEN REGIMEN_NO REGIMEN_START REGIMEN_END
773 X 1 2013-01-22 00:00:00 2013-04-22 00:00:00
773 X 2 2013-06-02 00:00:00 2013-10-28 00:00:00
773 X+Y 3 2013-10-28 00:00:00 2014-01-22 00:00:00
773 X 4 2014-01-22 00:00:00 2014-03-12 00:00:00

注意:中间有一个日期:2013-04-22 至 2013-06-02,患者没有服用任何药物。

我不明白如何使用 group_concat 来分隔日期和组合药物。谁能帮我解决这个问题。先感谢您。

【问题讨论】:

  • 你的主键是什么?
  • 目前,这不包含任何主键。原因是所有数据都可能包含重复项,并且也很难创建复合键,因为同样的原因 - 重复的机会。我可以做的一件事是通过患者 ID 引入 row_numbers 分区。那么row_number和patient_id的组合可以认为是主键
  • 在我看来 (patient_id,drug_taken,episode) 必须构成一个 UNIQUE 值
  • 你用的是什么版本的 MySQL?
  • 是的,我猜也可以使用。抱歉,我错过了。

标签: mysql group-concat


【解决方案1】:

我使用的是 MySQL 的旧版本,因此您需要对其进行更新以利用 8+ 中可用的工具,以构建与我的日历表等效的表,以及方案编号...

DROP TABLE IF EXISTS  my_table;

CREATE TABLE my_table
(PATIENT_ID INT NOT NULL
,DRUG CHAR(1) NOT NULL
,EPISODE INT NOT NULL
,EPISODE_START DATE NOT NULL
,EPISODE_END DATE NULL
,PRIMARY KEY(patient_id,drug,episode)
);

INSERT INTO my_table VALUES
(773    ,'X',1,'2013-11-28','2013-12-12'),
(773    ,'X',2,'2013-12-20','2014-01-06'),
(773    ,'Y',1,'2013-12-28','2014-01-03');

查询...

SELECT patient_id
     , MIN(dt) r_start
     , MAX(dt) r_end
     , drugs
     , i regimen
  FROM
    (
    SELECT dt
     , patient_id
     , drugs
     , CASE WHEN @prev_patient = patient_id 
            THEN CASE WHEN @prev_drugs = drugs 
                      THEN CASE WHEN @prev_dt = dt - INTERVAL 1 DAY 
                                THEN @i:=@i 
                                ELSE @i:=@i+1 END
                      ELSE @i:=@i+1 END
            ELSE @i:=@i+1 END i
     , @prev_patient := patient_id
     , @prev_drugs := drugs
     , @prev_dt := dt
      FROM 
      (
       SELECT dt
                   , x.patient_id
                   , GROUP_CONCAT(drug ORDER BY drug) drugs
                FROM dates 
                JOIN my_table x
                  ON dt BETWEEN episode_start AND episode_end
               GROUP
                  BY dt
                   , patient_id
               ORDER
                  BY patient_id, dt
        ) n JOIN (SELECT @prev_patient := null,@prev_drugs := null,@prev_dt := null,@i:=0) vars
        ) m 
        GROUP 
           BY patient_id
            , drugs
            , i
          ORDER BY patient_id, regimen;

+------------+------------+------------+-------+---------+
| patient_id | r_start    | r_end      | drugs | regimen |
+------------+------------+------------+-------+---------+
|        773 | 2013-11-28 | 2013-12-12 | X     |       1 |
|        773 | 2013-12-20 | 2013-12-27 | X     |       2 |
|        773 | 2013-12-28 | 2014-01-03 | X,Y   |       3 |
|        773 | 2014-01-04 | 2014-01-06 | X     |       4 |
+------------+------------+------------+-------+---------+

【讨论】:

  • 感谢您的回答。我正在尝试使用它,并会在一段时间内确认。只是有些疑问,我认为您从中选择“dt”属性的“日期”表是什么?
  • 它只是一个实用表 - 一个日期表。在 MySQL 8 中这不是必需的,因为您可以即时创建等效的数据集
  • 好的。所以基本上,日期表将包含 my_table 中所有剧集的开始日期,对吗?
  • 这只是一个日期表(从 1970 年到 2490 年,碰巧),但如前所述,在 8 中你不需要这个
猜你喜欢
  • 1970-01-01
  • 2021-04-01
  • 2021-12-10
  • 2020-01-07
  • 2011-02-03
  • 2021-09-21
  • 1970-01-01
  • 2020-08-01
  • 1970-01-01
相关资源
最近更新 更多