我正在使用SQL Server 2005 Analysis Services并且我正在尝试计算MDX查询内部的距离 - 这样我就能获得当前位置附近项目的计数。我用Latitude& amp;创建了一个维度。经度,并且还创建了一个.NET程序集来进行数学计算 - 但我很难在查询中完成所有工作。
我在100英里范围内查找物品的查询看起来像这样:
select FILTER([DimProducts].[Product].[Product],
ZipCalculatorLib.GetDistance(43.474208, [Zip].[Latitude], 96.687689, [Zip].[Longitude]) < 100) on rows,
[Measures].[RowCount] on columns
from MyCube;
我在.NET中的距离代码如下所示:
public static double GetDistance(double startLat, double endLat,
double startLong, double endLong)
{
return Math.Sqrt(Math.Pow(69.1 * (startLat - endLat), 2) + Math.Pow(Math.Cos(endLat / 57.3) * 69.1 * (startLong - endLong), 2));
}
然而,当我运行该查询时,我想出了零记录。如果我将距离从100更改为10000 - 我得到的计数与100英里半径内的计数相似。看起来.NET类没有做平方根 - 但是我已经多次测试了那段代码,看起来是正确的。
有没有人对我应该在哪里解决问题提出任何建议?
编辑: 我开始想知道是否可能没有正确地将纬度和经度传递到我的GetDistance函数中 - 所以我在那里添加了一行代码来抛出异常来向我展示它们是什么。我添加了以下内容:
throw new ArgumentException("endLat", string.Format("endLat: {0}, endLong: {1}", endLat, endLong));
现在,当我运行查询时,出现以下错误:
执行托管存储 程序GetDistance失败了 以下错误:异常已经发生 由一个目标抛出 invocation.endLat参数名称: endLat:1033,endLong:1033。
所以现在问题变成了:如何让我的实际纬度值通过滤波器中的该函数?看起来现在只传递语言代码。
答案 0 :(得分:2)
[Zip]。[Latitude]是一个成员表达式。为了将此函数作为数值传递给函数,SSAS将返回等效的([Zip]。[Latitude],Measures.CurrentMember)。而且你无法在MDX中直接过滤另一个维度。根据定义,不同的维度是完全独立的,并且OLAP表示每个产品都可能存在于每个Zip位置。
我怀疑逻辑必须如下所示:
select
NONEMPTY([DimProducts].[Product].[Product] *
FILTER([Zip].[Zip].[Zip] , ZipCalculatorLib.GetDistance(43.474208, [Zip].[Latitude].CurrentMember.MemberValue, 96.687689, [Zip].[Longitude].CurrentMember.MemberValue) < 100),[Measures].[RowCount]) on rows, [Measures].[RowCount] on columns
from MyCube;
这将获得纬度/经度在100英里范围内的所有Zip成员,与产品交叉连接,然后返回具有非空RowCount的那些。
答案 1 :(得分:1)
您如何确定以英里计算?
我不确定SQL Server 2008是否可用,如果是,您应该使用其地理数据类型来计算距离。
如果没有,请检查SharpMap和Proj.Net等库 - 它们可以让您构建真正的地理点并计算这些对象之间的准确距离。
答案 2 :(得分:1)
我最终使用子多维数据集解决了我的问题。通过创建子多维数据集,我能够过滤距离 - 然后在那之后只选择我正在寻找的维度。这就是我最终的结果......
create subcube MyCube as
select Filter
(
(
[DimLocation].[Latitude].[Latitude],
[DimLocation].[Longitude].[Longitude]
),
(
ZipCalculatorLib.GetDistance(
43.474208,
[DimLocation].[Latitude].CurrentMember.MemberValue,
96.687689,
DimLocation.Longitude.CurrentMember.MemberValue) < 100
)
) on 0 from MyCube;
select DimProducts.Product.Product on rows,
Measures.RowCount on columns
from MyCube;