Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server 如何编写一个TVF,它接受3个参数并返回一个表,其中包含与另一个表中的条件匹配的行的ID_Sql Server_User Defined Functions - Fatal编程技术网

Sql server 如何编写一个TVF,它接受3个参数并返回一个表,其中包含与另一个表中的条件匹配的行的ID

Sql server 如何编写一个TVF,它接受3个参数并返回一个表,其中包含与另一个表中的条件匹配的行的ID,sql-server,user-defined-functions,Sql Server,User Defined Functions,我是表值函数的新手,在开始使用这个函数时遇到了困难。 我正在尝试创建一个接受3的函数parameters@Lat十进制,@长十进制,@RangeInMiles int。 我要做的是从Locations表返回位置ID,该表位于传递的参数@RangeInMiles的半径范围内 位置表包括以下列: loc_ID PK标识 典型的地址信息 经度 位置纬度 因此,我们的想法是让这个函数使用传递的lat和long与Locations表中的lat和long进行比较,并返回传递半径内的id:@RangeInMi

我是表值函数的新手,在开始使用这个函数时遇到了困难。 我正在尝试创建一个接受3的函数parameters@Lat十进制,@长十进制,@RangeInMiles int。 我要做的是从Locations表返回位置ID,该表位于传递的参数@RangeInMiles的半径范围内

位置表包括以下列: loc_ID PK标识 典型的地址信息 经度 位置纬度

因此,我们的想法是让这个函数使用传递的lat和long与Locations表中的lat和long进行比较,并返回传递半径内的id:@RangeInMiles

到目前为止,我掌握的所有代码都在下面,但WHERE子句让我感到困惑。谢谢你的帮助

CREATE FUNCTION dbo.GetAvailableSalesByDistance(@Lat decimal, @Long decimal, @RangeInMiles int)
RETURNS @LocationIds Table
(loc_ID int)
AS
BEGIN INSERT @LocationIds
SELECT Locations.loc_ID
FROM Locations
WHERE 
RETURN
END

你可以试试下面的毕达哥拉斯:

CREATE FUNCTION dbo.GetAvailableSalesByDistance(@Lat decimal, @Long decimal, @RangeInMiles int)
RETURNS @LocationIds Table
(loc_ID int)
AS
BEGIN INSERT INTO@LocationIds
SELECT Locations.loc_ID
FROM Locations as l
WHERE (SQRT(SQUARE(l.loc_latitude-@Lat)+SQUARE(l.loc_longitude-@Long))<=@RangeInMiles)
RETURN
END
编辑: 要正确使用,您可以使用haversine:

CREATE FUNCTION dbo.GetAvailableSalesByDistance(@Lat decimal, @Long decimal, @RangeInMiles int)
    RETURNS @LocationIds Table
    (loc_ID int)
    AS
    BEGIN INSERT INTO@LocationIds
    SELECT Locations.loc_ID
    FROM Locations as l
    WHERE 
(2 * 3961 * asin(sqrt((sin(radians((l.loc_latitude - @Lat) / 2))) ^ 2 + cos(radians(@Lat)) * cos(radians(l.loc_latitude)) * (sin(radians((l.loc_longitude - @Long) / 2))) ^ 2))) <=@RangeInMiles)
    RETURN
    END

它未经测试,来自此

您的insert语句和updated子句可能是:

INSERT @LocationIds
        SELECT
            Locations.loc_ID 
        FROM
            Locations 
        WHERE
            SQRT(SQUARE(loc_longitude - @Long) + SQUARE(loc_latitude - @Lat)) <= @RangeInMiles

这比@Nikolaus发布的要复杂得多,纬度和经度是在一个地球球体上,不以英里表示,所以毕达哥拉斯的三元组在这里不适用。下面,我们将在SQL Server中获得以下函数来计算距离:

CREATE FUNCTION dbo.spatialDistance(@lat1 DECIMAL, @lon1 DECIMAL, @lat2 DECIMAL, @lon2 DECIMAL)
RETURNS TABLE
AS
RETURN (
    SELECT 6371 * Calc2.c AS DistanceKm
         , 3958.8 * Calc2.c AS DistanceMi
      FROM (SELECT RADIANS(@lat1) AS Lat1
                 , RADIANS(@lat2) AS Lat2
                 , RADIANS(@lat2 - @lat1) AS dLat
                 , RADIANS(@lon2 - @lon1) AS dLon) conv
     CROSS
     APPLY (SELECT a = SQUARE(SIN(dLat/2.0)) + SQUARE(SIN(dLon/2.0)) * COS(Lat1) * COS(Lat2)) Calc1
     CROSS
     APPLY (SELECT c = 2 * ATN2(SQRT(Calc1.a), SQRT(1 - Calc1.a))) AS Calc2
)
然后,您可以编写所需的函数,如下所示:

CREATE FUNCTION dbo.GetAvailableSalesByDistance(@Lat decimal, @Long decimal, @RangeInMiles int)
RETURNS Table
AS
RETURN (
    SELECT l.loc_id
      FROM Locations AS l
     CROSS
     APPLY dbo.spatialDistance(l.loc_latitude, l.loc_longitude, @Lat, @Long) dist
     WHERE dist.DistanceMi <= @RangeInMiles
)  

注意,我使用的是内联表值函数。像您在问题中使用的标量函数和多语句TVF对性能很糟糕,不应该使用

看来你需要毕达哥拉斯。三角形函数。谢谢你@Nikolaus。我尝试了您的方法,在调用函数时遇到以下错误:将数据类型nvarchar转换为数字时出错。这是我的电话:从GetAvailablesAlessByDistance34.10、84.52中选择*,5@JP1有可能是loc_latidude或/和loc_longidude属于nvarchar类型吗?你说得对,他们是!对于这个函数,哪一个更好:在“更改函数本身”的“位置”表中切换Lat和Long的数据类型?通常,它也应该以这种方式工作,但可能您有不能转换为十进制的数据。就像两列中的一列中的字母一样。@JP1如果您有无效数据,您可以尝试查找。谢谢您的帮助!这是有道理的。我仍然得到一个错误,当我运行函数调用时,它无法将varchar转换为numeric。思想?将数据类型nvarchar转换为数字时出错。这是我的电话:从GetAvailablesAlessByDistance34.10、84.52中选择*,5@JP1如何定义位置表?位置纬度和位置经度是nvarchar?如果是这样的话,试试@Nikolaus发布的CONVERT查询应该会显示这些信息。在创建我的版本之前,您可能忘记删除GetAvailablesAlessByDistance的早期版本?是的,它们是nvarchar。我必须找到一种方法将这些列转换为数字,这似乎是真的。再次感谢您的支持help@JP1他们应该自动转换,有些只是失败。您是否尝试过从TRY_CONVERTDECIMAL,loc_latitude为空或TRY_CONVERTDECIMAL,loc_latitude为空的位置选择*?这应该列出所有无法转换的记录。也许用逗号代替点作为小数点分隔符?
CREATE FUNCTION dbo.GetAvailableSalesByDistance(@Lat decimal, @Long decimal, @RangeInMiles int)
RETURNS Table
AS
RETURN (
    SELECT l.loc_id
      FROM Locations AS l
     CROSS
     APPLY dbo.spatialDistance(l.loc_latitude, l.loc_longitude, @Lat, @Long) dist
     WHERE dist.DistanceMi <= @RangeInMiles
)