#mysql #join
#mysql #Присоединиться
Вопрос:
Итак, у меня есть таблица переводов, которая содержит различные представления названия места. Я присоединяюсь к этой таблице на placeId
, где эта таблица служит правой стороной (левая сторона содержит информацию о place
).
Однако объединение по placeId приводит к возможному большему количеству переводов, см. Таблицу ниже. Содержимое preferredName / shortName / historicName равно 0 или 1. Однако нет правила, согласно которому каждый перевод должен содержать как минимум 1 запись с preferredName=1
.
Итак, что я получаю в итоге: как я могу выбрать только 1 из этих переводов, в частности:
- если запись существует с
preferredName=1
: используйте это - иначе, если запись существует с
shortName=1
: используйте это - иначе, если ни одна из них не является истинной (поэтому обе равны 0), выберите эту запись
.
--------------- --------- ------------------ --------------- ----------- --------------
| translationId | placeId | alternateName | preferredName | shortName | historicName |
--------------- --------- ------------------ --------------- ----------- --------------
| 4832 | 554 | 'New York' | 1 | 0 | 0 |
| 4833 | 554 | 'NY' | 0 | 1 | 0 |
| 4834 | 554 | 'New York City' | 0 | 0 | 0 |
--------------- --------- ------------------ --------------- ----------- --------------
Есть какие-нибудь подсказки? В основном это сводится к фильтрации нескольких совпадений в правой таблице до 1 записи в левой таблице.
Комментарии:
1. Упорядочить по «preferredName» и «ShortName», а затем выбрать первый результат 😉
2. как бы вы это сделали, когда сопоставляете 10 мест с этими переводами; в этом случае я хочу вернуть 10 записей (при этом каждая запись имеет соответствующий перевод в виде поля)
3. Вы можете выполнить объединение по подзапросу ‘select … из … упорядочить по …’ и, возможно, ‘ограничить 1’
4. я просто добавляю ответ, чтобы показать вам запрос, к которому вам нужно присоединиться 😉
Ответ №1:
Вы могли бы присоединиться 3 раза с разными условиями и объединить результаты:
select
a.*,
coalesce(name1.alternateName, name2.alternateName, name3.alternateName) as alternateName
from _table1_ as a
left join _table2_ as name1 on (a.placeId = name1.placeId and name1.preferredName=1)
left join _table2_ as name2 on (a.placeId = name2.placeId and name2.shortName=1)
left join _table2_ as name3 on (a.placeId = name3.placeId and name3.preferredName=0 and name3.shortName=0)
group by a.placeId
Комментарии:
1. я попробую это через мгновение; только 1 вещь: пары 1-1, 1-0, 0-1 и 0-0 могут существовать для preferredName / shortName (пары могут даже существовать в два раза, но тогда мы можем просто взять любую). Таким образом, он должен возвращать 1-1 перед 1-0, 1-0 перед 0-1 и 0-1 перед 0-0
Ответ №2:
Следуя моему предыдущему комментарию, вы можете отправить свой запрос на объединение в виде подзапроса.
попробуйте это :
SELECT * FROM mytable WHERE placeId = 554 ORDER BY preferredName DESC, shortName DESC;
он упорядочит результаты точно так, как вы хотите, с вашими предпочтениями. Просто добавьте ограничение 1, и вы правы!
SELECT * FROM mytable WHERE placeId = 554 ORDER BY preferredName DESC, shortName DESC LIMIT 1;
итак, просто добавьте свою первую часть запроса и присоединитесь к этому;)
РЕДАКТИРОВАТЬ : следующее относится к комментарию
LEFT OUTER JOIN
(SELECT * FROM alternatename
WHERE isoLanguage="NL" AND geonameid = a1.geonameid
ORDER BY isPreferredName DESC, isShortName DESC
LIMIT 1
)
AS alternate10
ON
alternate10.geonameid = a1.geonameid
Комментарии:
1. хм, да, похоже, это решает проблему; однако: я использую довольно большой набор данных, и я только что встроил этот подзапрос в свой основной запрос, и это добавило 13 секунд ко времени выполнения.
2. Если вы хотите, чтобы мы попытались оптимизировать ваш запрос, можете ли вы показать нам свой основной запрос? Этот запрос выполняется довольно быстро, поэтому я думаю, что нам нужно поработать над вашим основным и, возможно, найти, какой индекс может быть полезен в вашем случае.
3. pastebin.com/tqG0N5ds это общая идея. Примечание: полнотекстовый поиск (СООТВЕТСТВИЕ / ПРОТИВ) не является виновником. Запрос выполняется за 50 мс или около того, когда не выполняются подзапросы
4. Я вижу 2 возможных способа улучшить это: 1 => добавить условие g.geonameid внутри wehre в подзапросе. Таким образом, порядок по будет работать с действительно небольшим объемом данных. (то же самое для вас a1 или a2) «ГДЕ isoLanguage =»NL» и geonameid = g.geonameid»
5. я думаю, что выберу решение для объединения; я немного повозился с подзапросами, и они, похоже, недостаточно оптимизированы mysql. к сожалению, набор данных, с которым я работаю, не самый абстрактный, поэтому я не могу избежать необходимости 3 раза присоединяться к одной и той же таблице. 3 подзапроса в этом случае снизят производительность