跨案例选择不同计数

Posted

技术标签:

【中文标题】跨案例选择不同计数【英文标题】:Select distinct count across cases 【发布时间】:2015-11-11 11:15:02 【问题描述】:

我有一个带有VITALS 表的患者数据库。此表包含每个患者唯一的 patient ID (PATID)height variable (HT)。单个患者可能记录了>1 身高。

我正在尝试返回在高度范围内和跨高度范围 (e.g., 68-72", 72-76", etc.) 的唯一 PATIDs 计数。每个PATID 都应计入*only once*。但是我发现,如果患者记录了多个身高,他们将在一个范围内计算一次,但如果他们的身高跨越范围,他们将被计算两次 - 每个范围一次。

例如,如果患者的身高记录为 68、72 和 73,他们将在 68-72 范围内计数一次,在 72-76 范围内计数一次。我可以判断这是因为我们有 3054 个唯一 PATID,但查询返回的计数总和 >5000。

我的代码是:

SELECT 
    CASE
        when "HT" >0 and "HT" <=4 then '0-4'
        when "HT" >4 and "HT" <=8 then '4-8'
        when "HT" >8 and "HT" <=12 then '8-12'
        when "HT" >12 and "HT" <=16 then '12-16'
        when "HT" >16 and "HT" <=20 then '16-20'
        when "HT" >20 and "HT" <=24 then '29-24'
        when "HT" >24 and "HT" <=28 then '24-28'
        when "HT" >28 and "HT" <=32 then '28-32'
        when "HT" >32 and "HT" <=36 then '32-36'
        when "HT" >36 and "HT" <=40 then '36-40'
        when "HT" >40 and "HT" <=44 then '40-44'
        when "HT" >44 and "HT" <=48 then '44-48'
        when "HT" >48 and "HT" <=52 then '48-52'
        when "HT" >52 and "HT" <=56 then '52-56'
        when "HT" >56 and "HT" <=60 then '56-60'
        when "HT" >60 and "HT" <=64 then '60-64'
        when "HT" >64 and "HT" <=68 then '64-68'
        when "HT" >68 and "HT" <=72 then '68-72'
        when "HT" >72 and "HT" <=76 then '72-76'
        when "HT" >76 and "HT" <=80 then '76-80'
        when "HT" >80 and "HT" <=84 then '80-84'
        when "HT" >84 and "HT" <=88 then '84-88'
        when "HT" IS NULL then 'Null'
        else '>88'    
    END AS "Height Range",            
    COUNT(DISTINCT vital."PATID") AS "Count"
FROM dbo."VITAL" vital
GROUP BY 1;

【问题讨论】:

当患者属于多个 HT 范围时,为什么会首选一个而不是另一个?似乎问题定义和查询都缺少该规则。也许您想要PATID,max(HT) GROUP BY 1,然后将其分类为范围。 if a patient has height recorded as 68, 72, and 73 ... 显然,您必须定义要选择的行。并始终提供您的 Postgres 版本。 【参考方案1】:

您可以在子查询中折叠重复项进行计数之前:

SELECT CASE
        WHEN "HT" IS NULL THEN 'Null'
        WHEN "HT" <= 4  THEN '0-4'
        WHEN "HT" <= 8  THEN '4-8'
        WHEN "HT" <= 12 THEN '8-12'
        WHEN "HT" <= 16 THEN '12-16'
        WHEN "HT" <= 20 THEN '16-20'
        WHEN "HT" <= 24 THEN '29-24'
        WHEN "HT" <= 28 THEN '24-28'
        WHEN "HT" <= 32 THEN '28-32'
        WHEN "HT" <= 36 THEN '32-36'
        WHEN "HT" <= 40 THEN '36-40'
        WHEN "HT" <= 44 THEN '40-44'
        WHEN "HT" <= 48 THEN '44-48'
        WHEN "HT" <= 52 THEN '48-52'
        WHEN "HT" <= 56 THEN '52-56'
        WHEN "HT" <= 60 THEN '56-60'
        WHEN "HT" <= 64 THEN '60-64'
        WHEN "HT" <= 68 THEN '64-68'
        WHEN "HT" <= 72 THEN '68-72'
        WHEN "HT" <= 76 THEN '72-76'
        WHEN "HT" <= 80 THEN '76-80'
        WHEN "HT" <= 84 THEN '80-84'
        WHEN "HT" <= 88 THEN '84-88'
        ELSE                 '>88'    
    END AS "Height Range",            
    count(*) AS "Count"  -- DISTINCT not needed any more
FROM (
   SELECT DISTINCT ON ("PATID")  -- get greatest "HT" per patient
          "PATID", "HT"
   FROM   dbo."VITAL"
   ORDER  BY "PATID", "HT" DESC NULLS LAST
   ) sub
GROUP BY 1;

我还从您的 CASE 语句中删除了多余的检查 - 假设不可能出现负高度(您应该有一个 CHECK 约束)。

DISTINCT ON的详细解释:

Select first row in each GROUP BY group?

或者在子查询中使用聚合,例如@jpw suggested。

【讨论】:

我在想子查询可能是要走的路。我对 SQL 很陌生,所以我只想仔细检查一下 - 在您的示例中,我们实际上是在创建一个 PATID 和 HT 表,按 HT 降序排列。然后我们选择不同的 PATID。 SELECT ON 表示我们正在选择与 PATID(也就是该 PATID 的最大高度)关联的 HT 的第一个实例。谢谢! @Melanie:ORDER BY 只需要结合DISTINCT ON 选择最大的"HT"。是的,你基本上明白了。我添加了详细说明的链接。【参考方案2】:

如果患者有多个记录,您必须选择所需的记录。

一种解决方案是将源更改为仅获得最大高度,如下所示:

FROM (select "PATID", max("HT") "HT" from dbo."VITAL" GROUP BY "PATID") vital

或者您可以取记录的最小值或平均值 - 适当的解决方案取决于您的要求。

【讨论】:

以上是关于跨案例选择不同计数的主要内容,如果未能解决你的问题,请参考以下文章

如何使用嵌套案例查询获得不同的计数?

group_by 跨多个列的唯一计数

选择多个不同条件的计数,只计数不同,在一行中返回结果

在 cassandra 中选择不同计数的方法是啥?

跨网络同步计数器

在 Vuejs 中跨不同组件共享数据