Как выделить отдельный столбец, но вернуть все столбцы с формулой acos-cos-radians - PullRequest
0 голосов
/ 23 апреля 2020

Я хочу получить таблицу с именем supplier_products, в которой есть следующие столбцы

ID Item_id supplier_id variant_id  price    lat        lng   serving_radius(in km)

1     1      2            12       22.00  26.11360000 85.39430000    1
2     1      3            12       44.00  26.11360000 85.39430000    4
3     1      2            13       25.00  26.11360000 85.39430000    4
4     1      3            13       23.00  26.11360000 85.39430000    4

Теперь для поиска продуктов поставщика вблизи широты и долготы скажем ($lat = 26.1136;$long = 85.3643;). я использовал этот запрос

SELECT *, (6371 * acos(cos(radians('$lat')) * cos(radians(lat)) * cos( radians(lng) - radians('$long')) + sin(radians('$lat')) * sin(radians(lat)))) AS distance FROM supplier_products HAVING distance <= serving_radius ORDER BY distance")

Приведенный выше запрос возвращает все строки, которые обслуживают входные данные $lat & $long.

Но теперь я хочу вернуть все столбцы только тех строк, которые имеют отличный вариант_идентификатора, который служит для ввода $lat & $long

Я пытался использовать GROUP BY -

SELECT *, (6371 * acos(cos(radians('$lat')) * cos(radians(lat)) * cos( radians(lng) - radians('$long')) + sin(radians('$lat')) * sin(radians(lat)))) AS distance FROM supplier_products GROUP BY variant_id HAVING distance <= serving_radius")

Но это исключает некоторые нужные строки, так как GROUP BY выполняется перед предложением HAVING. Таким образом, это устраняет некоторые обязательные строки, которые находятся в радиусе обслуживания.

Я использую PHP & MYSQL

РЕДАКТИРОВАТЬ - я хочу это в качестве моего вывода

ID Item_id supplier_id variant_id  price    lat        lng   serving_radius(in km)

2     1      3            12       44.00  26.11360000 85.39430000    4
3     1      2            13       25.00  26.11360000 85.39430000    4

Поскольку строка с ID-1 не служит для ввода $lat/$long

Но моя попытка дала следующий результат -

ID Item_id supplier_id variant_id  price    lat        lng   serving_radius(in km)

3     1      2            13       25.00  26.11360000 85.39430000    4

Поскольку GROUP BY исключил 2nd row

1 Ответ

0 голосов
/ 23 апреля 2020

Ваше требование все еще не выполнено, если вы хотите получить предсказуемые результаты. Вы призываете выбрать только один ряд из нескольких. Почему желаемый результат показывает id = 3, а не id = 4? Я думаю, вы выбрали один из двух случайным образом.

Этот запрос (https://www.db-fiddle.com/f/USMrhc8gLcRD2rAmuzYzH/0) сделает это за вас.

SET @lat := 26.120888;
SET @long := 85.364832;
SELECT ANY_VALUE(supplier_id), variant_id, ANY_VALUE(price)  
FROM  ( SELECT ID,
               (6371 * acos(cos(radians(@lat)) * cos(radians(lat)) *
                cos( radians(lng) - radians(@long)) + sin(radians(@lat)) * 
                sin(radians(lat)))) AS distance
          FROM supplier_products 
     ) t WHERE distance < serving_radius
GROUP BY variant_id

У него есть подзапрос, который нужно показать вариант вашей таблицы, который показывает расстояния от предоставленных значений @lat и @long. Он показывает ID и расстояние. Это оно. (https://www.db-fiddle.com/f/guagWYVXXaf7cPkbojj9KD/2)

        SELECT *, 
               (6371 * acos(cos(radians(@lat)) * cos(radians(lat)) *
                cos( radians(lng) - radians(@long)) + sin(radians(@lat)) * 
                sin(radians(lat)))) AS distance
          FROM supplier_products 

Затем он использует этот подзапрос во внешнем запросе с GROUP BY, см. Выше.

Но, поскольку вам нужен только один строка за вариант, и вы не сказали нам, как выбрать эту строку, если имеется несколько строк, запрос использует функцию ANY_VALUE () , чтобы выбрать одно из доступных значений для каждого столбца в вашем результате.

Версии MySQL старше 8.0 не нуждаются в функциях ANY_VALUE (), потому что из-за пресловутой нестандартной обработки GROUP 10 * GROUP *: , пожалуйста, прочтите это.

Осторожно: если вы разрешите MySQL использовать этот ANY_VALUE () материал, будь то явный или неявный, вы сведете ваших тестеров и пользователей с ума. Сегодня они иногда получают другие результаты, чем на прошлой неделе, и они удивляются, что они сделали не так. Пожалуйста, не делайте этого.

И еще одна вещь: ваша формула расстояния известна тем, что выбрасывает исключения на очень малых расстояниях. Убедитесь, что он никогда не пытается использовать ACOS () со значением больше 1, изменив его так, чтобы он использовал LEAST (). (https://www.db-fiddle.com/f/USMrhc8gLcRD2rAmuzYzH/1)

    (6371 * acos(LEAST(1.0,cos(radians(@lat)) * cos(radians(lat)) *
    cos( radians(lng) - radians(@long)) + sin(radians(@lat)) *
    sin(radians(lat)))))
...