Как написать TVF, который принимает 3 параметра и возвращает таблицу, которая включает идентификаторы строк, которые соответствуют критериям из другой таблицы - PullRequest
0 голосов
/ 31 марта 2019

Я новичок в табличных функциях, и у меня возникли проблемы с запуском этой функции. Я пытаюсь создать функцию, которая принимает 3 параметра (@Lat десятичный, @Long десятичный, @RangeInMiles int). Я хочу вернуть идентификаторы местоположения из таблицы Locations, которые находятся в радиусе переданного параметра: @ RangeInMiles.

Таблица Location включает следующие столбцы: loc_ID PK IDENTITY (Типичный адрес вещи) loc_longitude loc_latitude

Таким образом, идея состоит в том, чтобы эта функция использовала значения lat и long, которые были переданы, чтобы сравнить их с значениями lats и long в таблице Locations и вернуть те идентификаторы, которые находятся в пределах переданного радиуса: @ 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

Ответы [ 3 ]

1 голос
/ 31 марта 2019

Вы можете попробовать это, следуя Пифагору:

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

Если вы хотите найти ложные данные, вы можете попробовать это утверждение:

SELECT * FROM Locations
WHERE TRY_CONVERT(numeric, loc_latitude) IS NULL
OR TRY_CONVERT(numeric, loc_longitude) IS NULL

Edit: Чтобы сделать это правильно, вы можете использовать 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

Он не проверен и поступает из этого источника

0 голосов
/ 01 апреля 2019

Это намного сложнее, чем то, что написал @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 с несколькими утверждениями, которые вы использовали в своем вопросе, ужасны для производительности и не должны использоваться. Смотрите здесь для объяснения, если вы заинтересованы .

0 голосов
/ 31 марта 2019

Ваш оператор вставки с обновленным предложением может быть:

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