如何在PostgreSQL的值列表中选择具有匹配项的字符串的第一部分?
我正在处理医疗数据,我想找到特定患者的主要诊断 诊断都以逗号分隔的字符串形式列在一列中。例如“A10.3、B55.2、A10.1”。让我们调用此表患者和包含诊断列表的列诊断列表。我想创建一个新列,其中包含来自诊断列表的第一部分,该部分在不同的表中有一个匹配项,该表包含可被视为“主要”的诊断列表。让我们调用此表ICD10,并将主要诊断列表列为primary\u diag 我想要第一个匹配的原因是,diag_list已经根据症状的严重程度进行了排序。所以我试图找到最严重症状的诊断,也可以被认为是主要诊断如何在PostgreSQL的值列表中选择具有匹配项的字符串的第一部分?,sql,postgresql,string-matching,Sql,Postgresql,String Matching,我正在处理医疗数据,我想找到特定患者的主要诊断 诊断都以逗号分隔的字符串形式列在一列中。例如“A10.3、B55.2、A10.1”。让我们调用此表患者和包含诊断列表的列诊断列表。我想创建一个新列,其中包含来自诊断列表的第一部分,该部分在不同的表中有一个匹配项,该表包含可被视为“主要”的诊断列表。让我们调用此表ICD10,并将主要诊断列表列为primary\u diag 我想要第一个匹配的原因是,diag_list已经根据症状的严重程度进行了排序。所以我试图找到最严重症状的诊断,也可以被认为是主要
我试图首先将diag_列表转换为一个数组,该数组使用string_to_array,但找不到有条件地从这个新数组中选择第一个匹配项的方法。你会怎么做呢?还是有完全不同的方法可以得出更简单和/或更有效的相同结论?这很棘手。从Postgres 9.4开始,您就有了
unnest()
的和ordinality
关键字。这包括一个位置列。这与其他一些东西结合起来,可以满足您的需要:
select distinct on (p.patientid) p.*, d.*
from patients p, later
unnest(string_to_array(p.diag_list, ',')) with ordinality dp(code, ord) join
diagnoses d
on d.code = dp.code
order by p.patientid, ord asc;
毫不奇怪,Erwin Brandstetter对这个问题以及如何解决这个问题有着广泛的了解。一旦你有了
字符串到数组
,你就需要取消它。然后,您需要加入ICD10
,对于每个患者,首先进行诊断
假设我们有以下数据:
CREATE TABLE patients
(
patient_id integer PRIMARY KEY,
diag_list text NOT NULL
) ;
INSERT INTO patients
VALUES
(1, 'A10.3,B55.2, A10.1') ,
(2, 'A10.3, A10.1, C20.2') ;
CREATE TABLE ICD10
(
primary_diag text PRIMARY KEY,
diagnose text
) ;
INSERT INTO ICD10
VALUES
('B55.2', 'Something Bad'),
('A10.1', 'Somehitng Worse');
有了这些数据,我们可以开始查看您的数据:
SELECT
patient_id, trim(diag) AS diag, nr
FROM
patients
JOIN LATERAL unnest(string_to_array(diag_list, ','))
WITH ORDINALITY AS a(diag, nr) ON true ;
得到
+------------+-------+----+
| patient_id | diag | nr |
+------------+-------+----+
| 1 | A10.3 | 1 |
| 1 | B55.2 | 2 |
| 1 | A10.1 | 3 |
| 2 | A10.3 | 1 |
| 2 | A10.1 | 2 |
| 2 | C20.2 | 3 |
+------------+-------+----+
下一步:使用ICD10连接此数据
WITH patients_and_diags AS
(
SELECT
patient_id, trim(diag) AS diag, nr
FROM
patients
JOIN LATERAL unnest(string_to_array(diag_list, ','))
WITH ORDINALITY AS a(diag, nr) ON true
)
SELECT
patient_id, diag, nr, diagnose
FROM
patients_and_diags
JOIN ICD10 ON ICD10.primary_diag = patients_and_diags.diag ;
。。。并获得:
+------------+-------+----+-----------------+
| patient_id | diag | nr | diagnose |
+------------+-------+----+-----------------+
| 1 | B55.2 | 2 | Something Bad |
| 1 | A10.1 | 3 | Somehitng Worse |
| 2 | A10.1 | 2 | Somehitng Worse |
+------------+-------+----+-----------------+
现在,我们只需要为每个患者id提取最小的“nr”
下面的查询一步完成所有操作
WITH patients_and_diags AS
(
SELECT
patient_id, trim(diag) AS diag, nr
FROM
patients
JOIN LATERAL unnest(string_to_array(diag_list, ','))
WITH ORDINALITY AS a(diag, nr) ON true
)
, patients_and_ICD10 AS
(
SELECT
patient_id, diag, nr, diagnose
FROM
patients_and_diags
JOIN ICD10 ON ICD10.primary_diag = patients_and_diags.diag
)
, first_ICD10 AS
(
SELECT
patient_id, min(nr) AS nr
FROM
patients_and_ICD10
GROUP BY
patient_id
)
SELECT
patient_id, diag, diagnose
FROM
first_ICD10
JOIN patients_and_ICD10 USING(patient_id, nr) ;
。。。让你:
+------------+-------+-----------------+
| patient_id | diag | diagnose |
+------------+-------+-----------------+
| 1 | B55.2 | Something Bad |
| 2 | A10.1 | Somehitng Worse |
+------------+-------+-----------------+
你可以随时查看一切
使用一些窗口
函数可以缩短查询时间;但我认为这种循序渐进的方法更为明确 您可以使用unest
进行诊断。这意味着每个患者有一行诊断组合。使用generate_subscripts
在列表中添加该诊断的位置。(对于Postgres 9.4及更高版本,具有有序性更好,如其他答案中所示。)您可以使用该位置对诊断进行排序,并筛选列表中最高的主要诊断:
with normal_pat as
(
select name
, unnest(string_to_array(diag_list, ',')) as diag
, generate_subscripts(string_to_array(diag_list, ','),1) as pos
from patients
)
, numbered_pat as
(
select row_number() over (partition by name order by pos) rn
, *
from normal_pat
join diagnostics d
on normal_pat.diag = d.primary_diag
)
select name
, diag
, pos as position_of_diagnostic_in_list
from numbered_pat
where rn = 1
以下是or的一个工作示例。不幸的是,“第一个”是有条件的:“诊断列表中在不同表中有匹配项的第一部分”@Andomar…谢谢。这使问题变得更加棘手。请添加一些数据样本,包括请求的结果和答案。我认为min(nr)
最好使用窗口函数。我不知道rextester.com,看起来比sqlfiddle快得多!@Andomar:是的,可能只是获取窗口的第一个值()
,按患者分组和按nr排序。但我不确定是否进行了所有优化(以及太多的概念)立刻是最好的主意。我们不要;-)谢谢!这解决了我的问题,你的解释也很容易理解。我不知道带序数的
关键字,它可能会在我现在处理的数据的多种情况下派上用场。