Sql 使用Group By时计算Access 2007中位数的最佳方法

Sql 使用Group By时计算Access 2007中位数的最佳方法,sql,ms-access,ms-access-2007,median,Sql,Ms Access,Ms Access 2007,Median,我有一个表,其中包含一本书,然后是关于该书的多个价格(这是一个高度简化的示例): 结果: 帐面平均价格 第12.3333册 第25册 没有内置函数-因此您必须使用代码在记录中循环并自己计算中值 使用-有很多代码示例Jet SQL中没有中间值,除非它是在2007年添加的,但这里介绍了如何获得中间值。你需要 一些SQL SELECT DISTINCTROW Books.BOOK, Avg(Books.PRICE) AS [Avg Of PRICE] FROM Books GROUP BY Book

我有一个表,其中包含一本书,然后是关于该书的多个价格(这是一个高度简化的示例):

结果: 帐面平均价格 第12.3333册 第25册
没有内置函数-因此您必须使用代码在记录中循环并自己计算中值


使用-有很多代码示例

Jet SQL中没有中间值,除非它是在2007年添加的,但这里介绍了如何获得中间值。你需要

一些SQL

SELECT DISTINCTROW Books.BOOK, Avg(Books.PRICE) AS [Avg Of PRICE]
FROM Books
GROUP BY Books.BOOK;
和一个用户定义函数(UDF)


From:

中位数可以在MS Access中使用常规查询而不使用VBA进行计算。中位数是第50个百分位。因此,正常创建select查询;然后进入SQL视图,在选择关键字后包含“前50%”。对底部50%进行升序排序;按前50%降序排序。然后查找底部百分比结果集的最大值和顶部百分比结果集的最小值。这两者的平均值就是中位数。使用“前50%”时,请确保查询中的条件特定于计算中位数的结果集

我曾尝试使用非VBA方法,但它们都有一定的局限性,无法为更大的数据集提供最准确的结果。对于前50%Asc(最大)和前50%Desc(最小)方法,Access有一个限制,按升序排序时会忽略单个值。对于舍入,Access使用银行家舍入,因此它并不总是根据值本身向上舍入,如果要向上舍入或向下舍入,则需要添加+-0.00001的尾随值。我还尝试了另一个没有VBA的Rank()方法,Access在对至少有一对相同值的值进行排序时遇到问题。出于上述原因,我强烈建议坚持在VBA中创建自定义函数

首先,这是一个非常有用的起点,谢谢。UDF有一个小错误。在“rs.Move(rs.RecordCount/2)”之后,需要添加行“rs.movePrevious”。这将为您提供Excel计算的正确中位数。这是一个非常好的主意:)但是当行数为奇数时,您是否可以确保将顶部/底部50%的计数向上舍入?如果没有,理想的中值-正好在中间的值将被跳过。一些测试似乎表明,至少在大多数情况下,它是圆的。也就是说,在大型数据集上仍然非常慢。。。
SELECT DISTINCTROW Books.BOOK, Avg(Books.PRICE) AS [Avg Of PRICE]
FROM Books
GROUP BY Books.BOOK;
BOOK Avg Of PRICE BOOK1 12.3333333333333 BOOK2 5
SELECT Statistics.Month, Sum(([SentTo])) AS [Sum Sent], fMedian("Statistics","Month",[Month],"SentTo") AS [Median Sent]
FROM Statistics
GROUP BY Statistics.Month;
Function fMedian(SQLOrTable, GroupFieldName, GroupFieldValue, MedianFieldName)
Dim rs As DAO.Recordset

Set db = CurrentDb
Set rs1 = db.OpenRecordset(SQLOrTable, dbOpenDynaset)

If IsDate(GroupFieldValue) Then
    GroupFieldValue = "#" & GroupFieldValue & "#"
ElseIf Not IsNumeric(GroupFieldValue) Then
    GroupFieldValue = "'" & Replace(GroupFieldValue, "'", "''") & "'"
End If

rs1.Filter = GroupFieldName & "=" & GroupFieldValue
rs1.Sort = MedianFieldName

Set rs = rs1.OpenRecordset()
rs.Move (rs.RecordCount / 2)

If rs.RecordCount Mod 2 = 0 Then
    varMedian1 = rs.Fields(MedianFieldName)
    rs.MoveNext
    fMedian = (varMedian1 + rs.Fields(MedianFieldName)) / 2
Else
    fMedian = rs.Fields(MedianFieldName)
End If

End Function