1

我正在使用SQL Server 2005 Analysis Services,并且正在尝试计算 MDX 查询内的距离 - 这样我就可以获得当前位置附近的项目的计数。我已经用纬度和经度创建了一个维度,并且还创建了一个 .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 的执行失败,出现以下错误:调用的目标已引发异常。endLat 参数名称:endLat:1033,endLong:1033。

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

4

3 回答 3

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 的那些成员。

于 2009-10-28T00:55:48.360 回答
1

你怎么确定你是以英里为单位计算的?

我不确定 SQL Server 2008 是否可用,如果可用,您应该使用其地理数据类型来计算距离。

如果没有,请查看 SharpMap 和 Proj.Net 之类的库——它们可以让您建立一个真实的地理点并计算这些对象之间的准确距离。

于 2009-10-13T21:18:41.470 回答
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;
于 2009-11-03T20:00:43.540 回答