日期:2014-05-17  浏览次数:21167 次

取中位值
现有如下数据库
  fid pid coadcladcon  
RAA0370AA01 PRAA0370 1
RAA0370AA02 PRAA0370 2
RAA0370AA03 PRAA0370 3
RAA0370AA04 PRAA0370 4
RAA0370AA05 PRAA0370 5
RAA0370AA06 PRAA0370 6
RAA0370AB01 PRAA0371 1
RAA0370AB02 PRAA0371 2
RAA0370AB03 PRAA0371 3
RAA0370AB04 PRAA0371 4
RAA0370AB05 PRAA0371 5
RAA0370AB06 PRAA0371 6
RAA0370AB07 PRAA0371 7


现在要根据pid来取得相同pid的coadcladcon中位值,

得到一个新的临时表,如下数据:
  pid coadcladcon  
PRAA0370 4
PRAA0371 4


------解决方案--------------------
SQL code
create table tb(pid varchar(10),coadcladcon int)
insert into tb
 select 'PRAA0370',1 union all
 select 'PRAA0370',2 union all
 select 'PRAA0370',3 union all
 select 'PRAA0370',4 union all
 select 'PRAA0370',5 union all
 select 'PRAA0370',6 union all
 select 'PRAA0371',1 union all
 select 'PRAA0371',2 union all
 select 'PRAA0371',3 union all
 select 'PRAA0371',4 union all
 select 'PRAA0371',5 union all
 select 'PRAA0371',6 union all
 select 'PRAA0371',7 
 
 with cte as
 (
  select no=row_number() over(partition by pid order by getdate()),*,
         num=(select count(*) from tb where pid=a.pid)
       from tb a
 )
 select pid,coadcladcon 
from (select no1=row_number() over(partition by pid order by abs(no*1./(num+1)-0.5)),* from cte) t
 where no1=1
 /*
 pid        coadcladcon
---------- -----------
PRAA0370   4
PRAA0371   4

(2 row(s) affected)

------解决方案--------------------
SQL code
中位数(Median)统计学名词

 1、定义:一组数据按从小到大(或从大到小)的顺序依次排列,处在中间位置的一个数(或最中间两个数据的平均数,注意:和众数不同,中位数不一定在这组数据中)。    
 2、中位数的优缺点:中位数是样本数据所占频率的等分线,它不受少数几个极端值得影响,有时用它代表全体数据的一般水平更合适。  
 3、在频率分布直方图中,中位数左边和右边的直方图的面积应该相等,由此可以估计中位数的值。   
 4、中位数也可表述为第50百分位数,二者等价。   
 5、直观印象描述:一半比“我”小,一半比“我”大。

 

中位数的算法
   求中位数时,首先要先进行数据的排序(从小到大),然后计算中位数的序号,分数据为奇数个与偶数个两种来求.   
 中位数算出来可避免极端数据,代表着数据总体的中等情况。   
 如果总数个数是奇数的话,按从小到大的顺序,取中间的那个数   
 如果总数个数是偶数个的话,按从小到大的顺序,取中间那两个数的平均数


-- 测试表
CREATE TABLE test_median (
  Name  varchar(10),
  val   INT
);
GO

-- 测试数据.
INSERT INTO test_median
  SELECT 'A',  1000  UNION ALL
  SELECT 'A',  2000  UNION ALL
  SELECT 'A',  3000  UNION ALL
  SELECT 'A',  4000  UNION ALL
  SELECT 'A',  5000  UNION ALL
  SELECT 'B',  100   UNION ALL
  SELECT 'B',  200   UNION ALL
  SELECT 'B',  300   UNION ALL
  SELECT 'B',  400   UNION ALL
  SELECT 'B',  7000  UNION ALL
  SELECT 'B',  10000
GO

Name 为 A 的数据,有5条
Name 为 B 的数据,有6条


直接使用 SQL 语句来进行计算的处理

使用2个子查询来计算
1个子查询用来排序
1个子查询用于计算总数
然后根据总数的 奇/偶,来决定哪些行需要进行计算。


SELECT
  data_with_rownumber.Name,
  AVG(data_with_rownumber.val) AS median
FROM
  (
  SELECT
 ROW_NUMBER() OVER(PARTITION BY Name ORDER BY val) AS seq,
 Name,
 val
  FROM
 test_median
  ) data_with_rownumber JOIN
  (
  SELECT
 Name, COUNT(1) AS NumOfVal
  FROM
 test_median
  GROUP BY
 Name
  ) data_count
  ON (
 data_count.Name = data_with_rownumber.Name
 AND (
  (data_count.NumOfVal % 2 = 0 AND data_with_rownumber.seq IN (data_count.NumOfVal / 2, (data_count.NumOfVal / 2) + 1))
  OR
  (data_count.NumOfVal % 2 = 1 AND data_with_rownumber.seq = 1 + data_count.NumOfVal / 2)
  )
  )
GROUP BY
  data_with_rownumber.Name

Name       median
---------- -----------
A                 3000
B                  350

(2 行受影响)

 

使用  Visual C# SQL CLR  创建的聚合函数来处理

 

使用 VS2010,创建一个
Visual C# SQL CLR 数据库项目 命名为 MyMidNumber
在项目中添加一个 [聚合] 的类

代码如下:

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;


[Serializable]
[SqlUserDefinedAggregate(
 Format.UserDefined,