见贤思小齐,知足常乐呵

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

在网上搜到的一种算法是利用自增长变量进行排序,然后再根据位置序号取。感觉有些复杂了。

一.   group_concat来的省事些, 缺点是 group_concat默认有总长度限制,不能对太多的数求中位数。可以修改长度限制,也可以用第二种方法

1. 按顺序聚合,逗号分隔,并计数

group_concat( number order by number asc) 

2. 根据逗号拆分,判断奇偶数去截取中间位置的那个数

 

具体代码如下:

SELECT 
            doctor_name doctor,  -- 分组
	    count(1) patientNum,  -- 总数
	    group_concat(dnt order by dnt asc),
	    substring_index(SUBSTRING_INDEX(group_concat(dnt order by dnt asc),',',(count(1)+1) div 2),',',-1)  dnt,
	    case when count(1)%2=1 then substring_index(SUBSTRING_INDEX(group_concat(dnt order by dnt asc),',',(count(1)+1) div 2),',',-1) 
else (substring_index(SUBSTRING_INDEX(group_concat(dnt order by dnt asc),',',(count(1)+2) div 2),',',-1) + substring_index(SUBSTRING_INDEX(group_concat(dnt order by dnt asc),',',count(1) div 2),',',-1))/2 end mid_dnt FROM ( SELECT distinct doctor_name, record_id, dnt from rp_green_channel_patient_detaile where dnt is not null AND visit_day >= '2020-03-30' AND visit_day <= '2020-06-27' ) AS a group by doctor_name

 二.   组内排序

比如: 计算每个病种的住院费用中位数,数据如下

思路:

(1) 对每个病种下的,住院费用按照从小到大生成序号,生成a表
(2) 对每个病种的总人数进行计数, 生成b表
(3) a表和b表进行关联,取a表最中间的1个数或两个数:
     如果总数是奇数,那么 ceil(b表总人数/2) 或 floor(b表总人数/2 +1) 即为中间那个数的序号
     如果总数是偶数,那么中间两个数依次是 ceil(b表总人数/2)、floor(b表总人数/2 +1)
     所以两表关联后,取ceil(b表总人数/2) 或 floor(b表总人数/2 +1) 两个位置的数,再取平均值即为中位数


代码:

    select
      a.base_group_name,
      round(avg(total_fee),1) median_fee                              -- 对已取出的两个数求平均值
    from 
    ( 
           select 
                  x.*,
                  if(@p2=base_group_name,@r2:=@r2+1,@r2:=1) as rank,   -- 在每个病种内进行排序,生成序号
                  @p2:=base_group_name
           from 
           (
           select
                     base_group_name,
                    record_id,
                      total_fee
           from ads_gc_patient_detail
           )x
           inner join 
           (
                     SELECT @p2:=NULL,@r2:=0                         -- 排序方式的初始化参数
           ) y
           order by base_group_name,total_fee asc                    -- 组内根据住院总费用增序排列
    )a
    join 
    (  
           select
                  base_group_name,
                  count(1) cnt
           from ads_gc_patient_detail
             group by base_group_name
    )b 
    on a.base_group_name=b.base_group_name 
         and (floor(b.cnt/2+1)=a.rank or ceil(b.cnt/2)=a.rank)    -- 取中间的两个数(组总数为偶数)或一个数(组总数为奇数)
    group by a.base_group_name

 

posted on 2020-07-22 18:06  Suckseedeva  阅读(2465)  评论(1编辑  收藏  举报