Postgis: как сделать только один запрос с двумя запросами - PullRequest
1 голос
/ 02 ноября 2019

Trab db:

След - это пешеходная тропа

  create_table "traces", force: :cascade do |t|
    t.string "name"
    t.geometry "path", limit: {:srid=>4326, :type=>"line_string"}
  end

Pois db:

Poi - это достопримечательность (город, замок ... )

create_table "pois", force: :cascade do |t|
    t.string "address"
    t.string "address2"
    t.integer "zip_code"
    t.string "city"
    t.string "department"
    t.string "region"
    t.float "latitude"
    t.float "longitude"
    t.geography "lonlat", limit: {:srid=>4326, :type=>"st_point", :geographic=>true}
  end

При первом запросе я получаю массив POI (ptb => poi2) вокруг одной дорожки (tr) из одного POI (pta => poi1)

      SELECT
        ptb.* AS pois
        FROM traces tr, pois pta, pois ptb, locate_point_a
        WHERE tr.id = #{trace.id}
          AND pta.id = #{poi1.id}
          AND ST_DWithin(
          ST_LineSubstring(
          tr.path,
          ST_LineLocatePoint(tr.path, pta.lonlat::geometry) + (25 * 1000) / ST_Length(tr.path, false),
          ST_LineLocatePoint(tr.path, pta.lonlat::geometry) + (250 * 1000) / ST_Length(tr.path, false)
          )::geography,
          ptb.lonlat::geography,
          4000)

Со вторым запросом я вычисляю расстояние между одним POI и другими POI (на дорожке)

      SELECT
        ST_Distance(tr.path::geography, pta.lonlat::geography) +
        ST_Distance(tr.path::geography, ptb.lonlat::geography) +
        ST_Length(ST_LineSubstring(
          tr.path,
          least(ST_LineLocatePoint(tr.path, pta.lonlat::geometry), ST_LineLocatePoint(tr.path, ptb.lonlat::geometry)),
          greatest(ST_LineLocatePoint(tr.path, pta.lonlat::geometry), ST_LineLocatePoint(tr.path, ptb.lonlat::geometry))),false)  AS dst_line
        FROM traces tr, pois pta, pois ptb, locate_point_a, locate_point_b
        WHERE tr.id = #{trace.id}
          AND pta.id = #{poi1.id}
          AND ptb.id = #{poi2.id}

Я хотел бы сделать только один запрос и получить список POI вокруг дорожки (упорядоченныйпо расстоянию) и расстояние от одного POI до всех других POI из списка (из первого запроса).

Например:

Я начинаю в городе (pta). Я хотел бы пройти 25 км (расстояние) и знать, где я могу найти общежитие для сна на таком расстоянии. С первым запросом я могу получить список со всеми отелями (ptb), 4000 м вокруг трассы.

Например, для результата первого запроса я получаю неупорядоченный список poi.ids: [1, 7, 8, 3]

Но мне тоже нужно знать и отображать, сколько именно там километров. находятся между моей начальной точкой (pta) и каждым отелем (ptb). Они в 21 км, 22 км или 24 км ...?

Итак, в результате второго запроса я получаю эту информацию для каждого poi (из первого запроса):
[1 => 21.6] [7 => 26.2] [8 => 21.2] [3 => 20.4 ]

Два запроса выполняют свою работу (но индивидуально). Мне нужны те же результаты, но только с одним запросом.

Упорядоченный список всех отелей с пробегом:

[3 => 20,4 , 8 => 21.2 ,  1=> 21,6 , 7 => 26,2]

1 Ответ

0 голосов
/ 09 ноября 2019
  SELECT
    ST_Distance(tr.path::geography, pta.lonlat::geography) +
    ST_Distance(tr.path::geography, poi.lonlat::geography) +
    ST_Length(ST_LineSubstring(
      tr.path,
      least(ST_LineLocatePoint(tr.path, pta.lonlat::geometry), ST_LineLocatePoint(tr.path, poi.lonlat::geometry)),
      greatest(ST_LineLocatePoint(tr.path, pta.lonlat::geometry), ST_LineLocatePoint(tr.path, poi.lonlat::geometry))),false)  AS dst_line, poi.*
  FROM traces tr, pois pta, (
    SELECT poi.* AS pois
    FROM traces tr, pois pta, pois poi
    WHERE tr.id = #{trace.id}
    AND pta.id = #{poi.id}
    AND ST_DWithin(ST_LineSubstring(
            tr.path,
            ST_LineLocatePoint(tr.path, pta.lonlat::geometry) + (#{dist} * 1000) / (tr.length * 1000) ,
            1)::geography,
            poi.lonlat::geography,
            2000)
      ) as poi
    WHERE tr.id = #{trace.id}
    AND pta.id = #{poi.id}
    AND poi.id = poi.id
    ORDER BY dst_line ASC

Теперь мне нужно оптимизировать его: D

...