MDX地理距离计算

时间:2009-10-13 21:12:14

标签: sql-server-2005 ssas olap mdx

我正在使用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。

所以现在问题变成了:如何让我的实际纬度值通过滤波器中的该函数?看起来现在只传递语言代码。

3 个答案:

答案 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;