Рассчитать кратчайшее расстояние между многими точками с пространственной MySQL (путем обработки строк в цикле?) - PullRequest
0 голосов
/ 14 февраля 2019

I) ПРОБЛЕМА

Допустим, есть 4 таблицы:

Таблица: assignment_has_place

| assignment_id | place_id |
|---------------|----------|
| 1             | 1        |
| 2             | 4        |
| 2             | 5        |

Таблица: agent_has_place

| agent_id | place_id |
|----------|----------|
| 1        | 2        |
| 2        | 1        |
| 1        | 3        |
| 1        | 4        |
| 3        | 4        |
| 3        | 6        |

Таблица: assignment_has_agent

| assignment_id | agent_id |
|---------------|----------|
| 1             | 1        |
| 1             | 2        |
| 2             | 3        |

Таблица: место (данные испытаний)

| Place_id | Name        | Geodata                 |
|----------|-------------|-------------------------|
| 1        | New-York    | POINT(-74.0072 40.7131) |
| 2        | Los Angeles | POINT(-118.244 34.0522) |
| 3        | Boston      | POINT(-71.0589 42.3601) |
| 4        | Chicago     | POINT(-87.6298 41.8781) |
| 5        | Dallas      | POINT(-96.797 32.7767)  |
| 6        | Austin      | POINT(-97.7431 30.2672) |

Таким образом, у назначения может быть много мест, у агента может быть много (личных) мест (например, дом, работа, родительский дом и т. Д.), И у назначения может быть много агентов.

Я изучаю отношения между местами назначения агентов и агентскими (личными) местами.Затем Я хочу знать кратчайшее расстояние между каждым местом назначения агентов и всеми его (личными) местами .(Другими словами, я хочу найти ближайший агент (личное) место для каждого его места назначения и узнать расстояние между ними). ​​

II) ТЕКУЩИЙ ЗАПРОС

SELECT
    assignment_has_agent.agent_id AS agent,
    place.place_id AS place_of_assignment,

-- BEGIN. Calculate distance between agents places and agents places of assignment
    ST_Distance_Sphere(place.geodata, -- This is a geodata about a place of assignment

        -- BEGIN. Select geodata for all agents places
        (SELECT
            place.geodata -- This is a geodata about an agents place
        FROM
            place
        INNER JOIN agent_has_place -- Get geodata about agents place
        ON agent_has_place.place_id = place.place_id
        WHERE agent_has_place.agent_id = assignment_has_agent.agent_id
        LIMIT 1 -- Here the problem!!! Without LIMIT Mysql error "Subquery returns more than 1 row"
        )
        -- END. Select geodata for all agents places
    ) 
    AS shortest_distance
-- END. Calculate distance between agents places and agents places of assignment

    FROM
        assignment_has_place 
    LEFT JOIN assignment_has_agent -- Make a link between assignment and agent
        ON assignment_has_agent.assignment_id = assignment_has_place.assignment_id  
    LEFT JOIN place -- Get a geodata about the place of assignment
        ON place.place_id = assignment_has_place.place_id

    GROUP BY assignment_has_agent.agent_id, place.place_id

III) ТЕКУЩИЙ РЕЗУЛЬТАТ

| agent | place_of_assignment | shortest_distance  |
|-------|---------------------|--------------------|
| 1     | 1                   | 3935659.762302256  | -- Note: New-York<>Los Angeles
| 2     | 1                   | 0                  | -- Note: New-York<>New-York
| 3     | 4                   | 0                  | -- Note: Chicago<>Chicago
| 3     | 5                   | 1294952.4320354236 | -- Note: Dallas<>Chicago

В моем текущем запросе я должен добавить LIMIT 1 , в противном случае у меня ошибка mysql “Подзапрос возвращает более 1 ряд".(См. Код выше.) Это потому, что агент может иметь много (личных) мест.Таким образом, этот результат неверен, потому что он занимает только первую строку среди всех мест сотрудников (*).

IV) ОЖИДАЕМЫЙ РЕЗУЛЬТАТ

| agent | place_of_assignment | shortest_distance  |
|-------|---------------------|--------------------|
| 1     | 1                   | 306167.42792567355 | -- Note: New-York<>Boston
| 2     | 1                   | 0                  | -- Note: New-York<>New-York
| 3     | 4                   | 0                  | -- Note: Chicago<>Chicago
| 3     | 5                   | 293094.4286555507  | -- Note: Dallas<>Austin

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

V) ВОПРОС (S)

Как получить ожидаемый результат?Я полагаю, что не так сложно выбрать минимальное расстояние с помощью MIN ()?Но как мне пройти каждый ряд агентских (личных) мест?Нужно ли использовать цикл (курсор? Могу ли я использовать его здесь?) Или есть другой (более простой) способ сделать это?

Большое спасибо за любой совет!

СМОТРИ ДЕМО ЗДЕСЬ

...