中位值:例如1、2、3、4、5中位值应该是3,意思是排序后取中间的值
最低循环值
例如1、1、2、3、2.2、2.1最低循环值为1
最低循环值的取值方法应该是求小于平均值的至少两个相同的值,
如果没有相同值的话,再取小于平均值的几个数再求平均值,接近这个平均值的数为最小循环值!
如果没有这两个函数,用sql实现怎么实现!
最低循环值
例如1、1、2、3、2.2、2.1最低循环值为1
最低循环值的取值方法应该是求小于平均值的至少两个相同的值,
如果没有相同值的话,再取小于平均值的几个数再求平均值,接近这个平均值的数为最小循环值!
如果没有这两个函数,用sql实现怎么实现!
http://blog.csdn.net/liangCK/archive/2009/09/11/4542991.aspx
--最低循环值
declare @tb table(id float)
insert @tb select 1 union all select 1 union all select 2
union all select 3 union all select 2.2 union all select 2.1
select id from @tb
where id<(select avg(id) from @tb)
group by id having(count(*)>1)
create table #num(C1 varchar(10), C2 int)insert into #num
select 'A',3
union all select 'A',5
union all select 'A',5
union all select 'A',4
union all select 'B',3
union all select 'B',7
union all select 'B',6
--临时表
select identity(int,1,1) as autoid,a.C1,a.C2+B.C2 as C2 into #test from #num as a,#num as b
where a.C1=b.C1
order by a.C1,a.C2+B.C2
--结果
select C1, cast(
(select C2/2.0 FROM #test where C1=a.C1 and autoid in
(select min(autoid)+1+(max(autoid)-min(autoid))/2 from #test where C1=a.C1 ) )
as float) as C2
from #test as a
group by C1
--
C1 C2
---------- ----------------------
A 4.5
B 6
那个什么最低循环制貌似需求不清晰,需求不合理。
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
GOName 为 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.NameName 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, // 使用 UserDefined 序列化格式
IsInvariantToNulls = true, // 指示聚合是否与空值无关。
IsInvariantToDuplicates = false, // 指示聚合是否与重复值无关。
IsInvariantToOrder = false, // 指示聚合是否与顺序无关。
MaxByteSize = 8000) // 聚合实例的最大大小(以字节为单位)。
]
public struct Median : Microsoft.SqlServer.Server.IBinarySerialize
{
public void Init()
{
// 初始化.
dataList = new List<Decimal>();
} public void Accumulate(SqlDecimal Value)
{
// 新增一个数据
dataList.Add(Value.Value);
} public void Merge(Median Group)
{
// 新增一组数据.
dataList.AddRange(Group.dataList);
} public SqlDecimal Terminate()
{
// 首先排序.
dataList.Sort(); decimal middleVal = 0; if (dataList.Count > 0)
{
if (dataList.Count % 2 == 1)
{
// 当数量为奇数的时候.
// 中位数为中间的那个数字.
// 例如
// 1个数字, 中位为第1个
// 3个数字, 中位为第2个
// 5个数字, 中位为第3个
// 7个数字, 中位为第4个
middleVal = dataList[dataList.Count / 2];
}
else
{
// 当数量为偶数的时候.
// 中位数为 中间2个数的 算数平均
// 例如
// 2个数字, 中位为 (第1个 + 第2个) / 2
// 4个数字, 中位为 (第2个 + 第3个) / 2
// 6个数字, 中位为 (第3个 + 第4个) / 2
// 8个数字, 中位为 (第4个 + 第5个) / 2
middleVal =
(dataList[dataList.Count / 2 - 1]
+ dataList[dataList.Count / 2]) / 2;
}
} return new SqlDecimal(middleVal);
} // 这是分组的所有数据.
private List<Decimal> dataList;
/// <summary>
/// 使用 UserDefined 序列化格式
/// 通过 IBinarySerialize.Read 方法完全控制二进制格式。
/// 从用户定义类型 (UDT) 或用户定义聚合的二进制格式生成用户定义的类型或用户定义的聚合。
/// </summary>
/// <param name="r"></param>
public void Read(System.IO.BinaryReader r)
{
// 初始化数据.
dataList = new List<decimal>();
// 先读取总数量.
int size = r.ReadInt32();
// 依次读取数据,加入列表.
for (int i = 0; i < size; i++)
{
dataList.Add(r.ReadDecimal());
}
} /// <summary>
/// 使用 UserDefined 序列化格式
/// 通过 IBinarySerialize.Read 方法完全控制二进制格式。
/// 将用户定义的类型 (UDT) 或用户定义的聚合转换为其二进制格式,以便保留。
/// </summary>
/// <param name="w"></param>
public void Write(System.IO.BinaryWriter w)
{
// 先写入一个 总数量
w.Write(dataList.Count);
// 依次写入每一个数据.
foreach (Decimal data in dataList)
{
w.Write(data);
}
}
} C# 项目需要记得设置 目标框架为 .NET Framework 3.5
如果使用默认的 .NET Framework 4,可能无法成功的把编译好的 DLL 文件发布到 SQL Server 2008 上面去。在把编辑好的 DLL 文件,加入到数据库的程序集之后。
再执行下面的 SQL 语句。
CREATE AGGREGATE [dbo].[Median](@Value NUMERIC (18))
RETURNS NUMERIC (18)
EXTERNAL NAME [MyMidNumber].[Median]; 最后直接在 SQL 语句里面,使用新编写的聚合函数:SELECT
ISNULL(Name, '全部') AS 名称,
SUM(val) AS 合计,
AVG(val) AS 平均数,
dbo.Median(val) AS 中位数
FROM
test_median
GROUP BY
Name
WITH ROLLUP
名称 合计 平均数 中位数
---------- ----------- ----------- --------------------
A 15000 3000 3000
B 18000 3000 350
全部 33000 3000 2000(3 行受影响)
感觉挺麻烦的!有没有更简洁的办法!不用identity获取中间这两个值,有什么办法可以获取中间这两个值?
你的办法好像太麻烦了点,因为我要用存储过程调用存储过程,所以你这种办法不行! 代码也不是很好理解!
不用identity可以获取到中间这两个值吗?你这种方法挺实用!不过在我那存储过程中不好用!因为我的结果集挺复杂的!
值= Fixing_DT ,
Testingdate,
Class,
P01_HumanCount,
设备=case when @M01_Area='Cartridge' then M02_Line+'_'+M06_Station
else M06_Station
end,
平均值=(select avg(Fixing_DT) from T_ATT where Testingdate=b.Testingdate and M00_Family=b.M00_Family and M01_Area=b.M01_Area and M02_Line =b.M02_Line and M06_Station=b.M06_Station group by M00_Family,M01_Area,M02_Line,M06_Station,Class,Testingdate) ,
最大值=(select max(Fixing_DT) from T_ATT where Testingdate=b.Testingdate and M00_Family=b.M00_Family and M01_Area=b.M01_Area and M02_Line =b.M02_Line and M06_Station=b.M06_Station group by M00_Family,M01_Area,M02_Line,M06_Station,Class,Testingdate) ,
最小值=(select min(Fixing_DT) from T_ATT where Testingdate=b.Testingdate and M00_Family=b.M00_Family and M01_Area=b.M01_Area and M02_Line =b.M02_Line and M06_Station=b.M06_Station group by M00_Family,M01_Area,M02_Line,M06_Station,Class,Testingdate) ,
中位值=(),
Min_Cyc=(select min(t.aa) from (select Fixing_DT as aa from T_ATT as f where Testingdate=b.Testingdate and M00_Family=b.M00_Family and M01_Area=b.M01_Area and M02_Line =b.M02_Line and M06_Station=b.M06_Station and Fixing_DT<
(select avg(Fixing_DT) from T_ATT where Testingdate=f.Testingdate and M00_Family=f.M00_Family and M01_Area=f.M01_Area and M02_Line =f.M02_Line and M06_Station=f.M06_Station
group by M00_Family,M01_Area,M02_Line,M06_Station,Class,Testingdate)
group by M00_Family,M01_Area,M02_Line,M06_Station,Class,Testingdate,Fixing_DT having(count(Fixing_DT)>1)) t),
CT最小循环值= case when (select HandWork_DT from T_ATT_HW where M00_Family=b.M00_Family and M01_Area=b.M01_Area and M02_Line =b.M02_Line and M06_Station=b.M06_Station )is not null then
((select avg(Fixing_DT) from T_ATT where Testingdate=b.Testingdate and M00_Family=b.M00_Family and M01_Area=b.M01_Area and M02_Line =b.M02_Line and M06_Station=b.M06_Station group by M00_Family,M01_Area,M02_Line,M06_Station,Class,Testingdate))+
(select min(t.aa) from (select Fixing_DT as aa from T_ATT as f where Testingdate=b.Testingdate and M00_Family=b.M00_Family and M01_Area=b.M01_Area and M02_Line =b.M02_Line and M06_Station=b.M06_Station and Fixing_DT<
(select avg(Fixing_DT) from T_ATT where Testingdate=f.Testingdate and M00_Family=f.M00_Family and M01_Area=f.M01_Area and M02_Line =f.M02_Line and M06_Station=f.M06_Station
group by M00_Family,M01_Area,M02_Line,M06_Station,Class,Testingdate)
group by M00_Family,M01_Area,M02_Line,M06_Station,Class,Testingdate, Fixing_DT having(count(Fixing_DT)>1)) t) else
(select min(t.aa) from (select Fixing_DT as aa from T_ATT as f where Testingdate=b.Testingdate and M00_Family=b.M00_Family and M01_Area=b.M01_Area and M02_Line =b.M02_Line and M06_Station=b.M06_Station and Fixing_DT<
(select avg(Fixing_DT) from T_ATT where Testingdate=f.Testingdate and M00_Family=f.M00_Family and M01_Area=f.M01_Area and M02_Line =f.M02_Line and M06_Station=f.M06_Station
group by M00_Family,M01_Area,M02_Line,M06_Station,Class,Testingdate)
group by M00_Family,M01_Area,M02_Line,M06_Station,Class,Testingdate, Fixing_DT having(count(Fixing_DT)>1)) t)
end
into #T_A from T_ATT as b