Получить самый левый | правый | верхний | нижний пункт, содержащийся в поле - PullRequest
0 голосов
/ 03 апреля 2010

Я храню точки интереса (POI) в базе данных PostgreSQL и извлекаю их с помощью сценария PHP в приложение Android.Чтобы сократить использование Интернета, я хочу, чтобы мое мобильное приложение узнало, есть ли какие-либо точки в окрестности текущей отображаемой области.

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

В настоящее время я могу получить точки, которые находятся на «одном экране» (в области, охватываемой отображаемой в данный момент картой), используя:

SELECT * FROM ch WHERE loc <@ (box '((".-$latSpan.", ".$lonSpan."),(".$latSpan.", ".-$lonSpan."))' + point '".$loc."')

Теперь мне нужно знать четыре наиболее удаленные точки в каждом направлении, чем я будувозможность получения следующих четырех «более удаленных» точек.

Есть ли возможность получить эти точки (или блок) непосредственно из PostgreSQL (возможно, с использованием некоторой функции «агрегировать точки в блок»)?

1 Ответ

0 голосов
/ 03 апреля 2010

Вы можете использовать оператор расстояния до (<->) в сочетании с агрегатной функцией MIN, чтобы найти ближайшее расстояние, тем самым уменьшая проблему с поиском других столбцов для строки с минимальным количеством .Строго слева / справа от / выше / ниже операторов (<<, >>, |>>, <<|) можно использовать для ограничения точек одной стороной поля.Поскольку две разные точки могут иметь одинаковое расстояние, мы ограничим результат 1 строкой.Предполагая ориентацию экрана, где координаты увеличиваются вниз и вправо (вместо ориентации карты, которая увеличивает север и восток), мы получаем:

-- Above, or North
SELECT * FROM ch WHERE loc <<| screen AND (loc <-> screen) = (
  SELECT MIN(loc <-> screen) AS mindist FROM ch
    WHERE loc <<| screen
) LIMIT 1

-- Right, or East
SELECT * FROM ch WHERE loc >> screen AND (loc <-> screen) = (
  SELECT MIN(loc <-> screen) AS mindist FROM ch 
    WHERE loc >> screen
) LIMIT 1

-- Below, or South
SELECT * FROM ch WHERE loc |>> screen AND (loc <-> screen) = (
  SELECT MIN(loc <-> screen) AS mindist FROM ch
    WHERE loc |>> screen
) LIMIT 1

-- Left, or West
SELECT * FROM ch WHERE loc << screen AND (loc <-> screen) = (
  SELECT MIN(loc <-> screen) AS mindist FROM ch 
    WHERE loc << screen
) LIMIT 1

Обратите внимание, что ближайшая точка в горизонтальном направлении также может бытьближайшая точка в вертикальном направлении;то есть объединение вышеупомянутых четырех операторов может быть меньше четырех строк.

Мы можем получить четыре ближайших точки с помощью:

SELECT *, (loc <-> screen) AS distance FROM ch 
  WHERE NOT loc <@ screen
  ORDER BY distance
  LIMIT 4

Однако обратите внимание, что некоторые из ближайших точекможет быть в одном направлении друг с другом.

Мы можем получить ближайшую точку в целом с помощью

SELECT *, (loc <-> screen) AS distance FROM ch 
  WHERE distance = (
      SELECT MIN(loc <-> screen) AS mindist FROM ch
  )
  LIMIT 1

или

SELECT *, (loc <-> screen) AS distance FROM ch 
  WHERE NOT loc <@ screen
  ORDER BY distance
  LIMIT 1

При расчете минимума (или максимума) столбца, первый будет предпочтительным, поскольку СУБД может использовать индекс для столбца (если есть) и не нужно сканировать таблицу.Поскольку расстояние является расчетным значением, сканирование таблицы всегда необходимо, и запросы будут иметь аналогичную производительность. анализ запросов может вызвать какую-то другую причину, чтобы предпочесть утверждение, поэтому вы должны сделать это до выбора подхода.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...