Microsoft Access - SQL生成的字段评估为Text而不是Single数据类型

时间:2013-01-04 20:20:30

标签: sql ms-access types latitude-longitude

我有一个SQL语句(在Access中保存为“LocationSearch”),用于计算两点之间的距离,并将“距离”作为生成字段返回。

SELECT Int((3963*(Atn(-(Sin(LATITUDE/57.2958)*
    Sin([@lat]/57.2958)+Cos(LATITUDE/57.2958)*Cos([@lat]/57.2958)*
    Cos([@lng]/57.2958-LONGITUDE/57.2958))/Sqr(-(Sin(LATITUDE/57.2958)*
    Sin([@lat]/57.2958)+Cos(LATITUDE/57.2958)*Cos([@lat]/57.2958)*
    Cos([@lng]/57.2958-LONGITUDE/57.2958))*(Sin(LATITUDE/57.2958)*
    Sin([@lat]/57.2958)+Cos(LATITUDE/57.2958)*Cos([@lat]/57.2958)*
    Cos([@lng]/57.2958-LONGITUDE/57.2958))+1))+2*Atn(1)))*10)/10 AS Distance, *
FROM Locations
ORDER BY (3963*(Atn(-(Sin(LATITUDE/57.2958)*
    Sin([@lat]/57.2958)+Cos(LATITUDE/57.2958)*Cos([@lat]/57.2958)*
    Cos([@lng]/57.2958-LONGITUDE/57.2958))/Sqr(-(Sin(LATITUDE/57.2958)*
    Sin([@lat]/57.2958)+Cos(LATITUDE/57.2958)*Cos([@lat]/57.2958)*
    Cos([@lng]/57.2958-LONGITUDE/57.2958))*(Sin(LATITUDE/57.2958)*
    Sin([@lat]/57.2958)+Cos(LATITUDE/57.2958)*Cos([@lat]/57.2958)*
    Cos([@lng]/57.2958-LONGITUDE/57.2958))+1))+2*Atn(1)));

您看到的所有令人讨厌的数学代码都是使用纬度和经度坐标计算SQL语句中的距离(以英里为单位)。

但问题是,SQL语句生成的Distance字段似乎是以字符串形式返回的。如果我然后添加要求在0到45英里之间的位置的SQL代码,它将返回从“0”和“45”之间开始的任何距离值。这包括距离为“1017”英里的位置。显然,距离字段是文本字段,而不是数字字段。所以我不能使用“BETWEEN”声明。我也无法评估使用“<”和“>”因为它有同样的问题。

我将上面的SQL查询保存为名为“LocationSearch”的已保存查询。这样我可以对它运行二次查询,如下所示:

SELECT * FROM LocationSearch WHERE Distance < @MaxDistance

Access将询问@lat,@ long和@MaxDistance参数,然后将按记录集返回位置,按距离排序。但是,出现的问题是当我输入MaxDistance为45.当一个表包含美国西海岸的位置,@lat为47,@ long为-122(西雅图附近)时,Access返回以下内容:

enter image description here

另请注意,“距离”字段是右对齐格式的,因此它看起来像是一个数字字段,但由于某种原因,查询返回圣地亚哥的一个位置,距离为1,017英里。我的猜测是它将Distance字段评估为文本字段,而在ASCII比较中,我认为“1017”位于“0”和“45”之间。

另一件事:我使用ASP 3.0(经典)使用JET OLEDB 4.0访问此查询。

任何人都知道如何将距离字段定义为数字?

谢谢!

---编辑---

在下面的答案中使用HansUp的想法,我尝试了这个查询来强制Access将Distance字段视为单个精度数字:

SELECT * FROM LocationSearch WHERE CSng(Distance) < @MaxDistance

即使这样也返回了与以前完全相同的结果,其中包括位于1017英里外的圣地亚哥的位置。

3 个答案:

答案 0 :(得分:2)

如果找不到从Duration字段表达式返回数值而不是文本的方法,请将查询用作子查询,然后在包含的查询中转换Duration

SELECT CSng(sub.Duration) AS Duration_as_single
FROM
    (
        -- your existing query --
    ) AS sub
WHERE CSng(sub.Duration) BETWEEN 0 AND 45
ORDER BY 1;

这种方法也可以提供更好的ORDER BY ...如果这对任何事情都有意义。 : - )

答案 1 :(得分:1)

我在没有select *且没有FROMORDER BY子句的情况下尝试了您的查询。 我在SELECT中添加了一个额外的列,以证明字符串在访问网格中以左对齐方式返回。

SELECT Int((3963*(Atn(-(
Sin(LATITUDE/57.2958)*Sin([@lat]/57.2958)+Cos(LATITUDE/57.2958)*
Cos([@lat]/57.2958)*Cos([@lng]/57.2958-LONGITUDE/57.2958))/Sqr(-(Sin(LATITUDE/57.2958)*
Sin([@lat]/57.2958)+Cos(LATITUDE/57.2958)*Cos([@lat]/57.2958)*
Cos([@lng]/57.2958-LONGITUDE/57.2958))*(Sin(LATITUDE/57.2958)*
Sin([@lat]/57.2958)+Cos(LATITUDE/57.2958)*Cos([@lat]/57.2958)*
Cos([@lng]/57.2958-LONGITUDE/57.2958))+1))+2*Atn(1)))*10)/10 AS Distance, 
'test' as test

我被提示输入四个参数,但最后我得到了一个两列表:

enter image description here

由于右对齐的第一列和第二列(显然是一个字符串)是左对齐的,因此看起来访问确实将它作为数字返回给我。这是在Access 2010中。

- 的修改 -

我刚刚创建了一个名为Locations的新的双列表。它有一个字段id(自动编号)和一个字段Field1(文本)。我运行OP提供的原始查询,它工作正常(距离以数字形式返回)。

这导致了奇迹...... OP的Locations表是否有自己的距离字段,这是一个字符串?否则,问题必须出在调用SQL语句的代码中,而不是在语句或jet引擎本身中。

答案 2 :(得分:1)

好的,解决了!

HansUp,您的想法最终成为了解决方案。我尝试在SQL查询中的CSng()参数上添加@MaxDistance函数,这就是解决它的问题。

以下是修改后的辅助SQL查询:

SELECT * FROM LocationSearch WHERE CSng(Distance) < CSng(@MaxDistance)

感谢大家的帮助!你们都摇滚。

新年快乐。