Ваше «решение» не является допустимым SQL, но оно работает в MySQL.Однако вы не можете быть уверены, что это произойдет с будущим изменением кода оптимизатора запросов.Можно было бы немного улучшить, чтобы иметь только 1 уровень вложенности (все еще не допустимый SQL):
--- Option 1 ---
SELECT
c.*
, p.*
FROM
city AS c
JOIN
( SELECT *
FROM person
ORDER BY person_city_id
, person_name DESC
) AS p
ON c.city_id = p.person_city_id
GROUP BY p.person_city_id
Другой способ (допустимый синтаксис SQL, работает и в других СУБД) - создать подзапросвыбрать фамилию для каждого города и затем присоединиться:
--- Option 2 ---
SELECT
c.*
, p.*
FROM
city AS c
JOIN
( SELECT person_city_id
, MAX(person_name) AS person_name
FROM person
GROUP BY person_city_id
) AS pmax
ON c.city_id = pmax.person_city_id
JOIN
person AS p
ON p.person_city_id = pmax.person_city_id
AND p.person_name = pmax.person_name
Другим способом является самостоятельное объединение (таблицы person
) с трюком <
, который описывает @matumatic_coffee.
--- Option 3 ---
see @mathematical-coffee's answer
Еще один способ - использовать LIMIT 1
подзапрос для объединения city
с person
:
--- Option 4 ---
SELECT
c.*
, p.*
FROM
city AS c
JOIN
person AS p
ON
p.person_id =
( SELECT person_id
FROM person AS pm
WHERE pm.person_city_id = c.city_id
ORDER BY person_name DESC
LIMIT 1
)
. Это запустит подзапрос (в таблице person
) для каждого города, и будет эффективно, если у вас есть индекс (person_city_id, person_name)
для движка InnoDB или (person_city_id, person_name, person_id)
для движка MyISAM.
Существует одно существенное различие между этими опциями:
Оприоны 2 и 3 будут возвращать все связанные результаты (если у вас есть два или более человека в городе с одинаковым именем в алфавитном порядкепоследний, тогда будут показаны оба или все).
Опции 1 и 4 будут возвращать один результат на город, даже если есть связи.Вы можете выбрать, какой из них, изменив предложение ORDER BY
.
Какой вариант более эффективен, зависит также от распределения ваших данных, поэтому лучший способ - попробовать их все, проверить их планы выполнения.и найти лучшие индексы, которые работают для каждого из них.Индекс на (person_city_id, person_name)
, скорее всего, будет хорошим для любого из этих запросов.
С распределением я имею в виду:
У вас мало городов с большим количеством людей на город?(Я думаю, что варианты 2 и 4 будут вести себя лучше в этом случае)
Или много городов с небольшим количеством людей в городе?(вариант 3 может быть лучше с такими данными).