Я динамически создаю инструкцию SELECT, которая выбирает элемент и, возможно, несколько списков связанных элементов.
Конечной целью является объект в пространстве приложения с массивами идентификаторов для каждого из связанных типов.
Использование списка JOIN'ов довольно просто:
SELECT items.*, item_has_related1.related1_id, item_has_related2.related2_id, ...
FROM (items)
LEFT JOIN item_has_related1 ON item_has_related1.item_id = items.id
LEFT JOIN item_has_related2 ON item_has_related2.item_id = items.id
... potentially many more
WHERE items.id = $itemId;
LEFT JOIN
используется, потому что некоторые отношения могут быть пустыми.
Наиболее очевидная проблема с этим состоит в том, что количество возвращаемых строк является произведением числа совпадений во всех объединениях. С несколькими объединенными таблицами это число может стать очень большим. Если бы было пять таблиц с шестью совпадениями в каждой, было бы 6 ^ 5 строк! Вторичная проблема заключается в том, что обработка возвращаемых строк является более сложной, поскольку мне приходится выкапывать уникальные значения в каждом столбце.
В качестве альтернативы я написал что-то вроде этого, что по сути делает отдельный запрос для каждого JOIN:
SELECT items.*, item_has_related_1.related1_id, NULL as related2_id, ...
FROM (items)
JOIN item_has_related_1 ON item_has_related_1.item_id = items.id
WHERE items.id = $itemId
UNION
SELECT items.*, NULL as related1_id, item_has_related_2.related2_id, ...
FROM (items)
JOIN item_has_related_2 ON item_has_related_2.item_id = items.id
WHERE items.id = $itemId
Количество строк, возвращаемых таким образом, является суммой количества совпадений во всех объединениях. Однако время подготовки запроса намного больше, и поэтому для небольших наборов данных этот метод менее эффективен. Я пытался эмпирически определить определение «поменьше», но с моими данными испытаний я не уверен, что мои результаты значимы.
Есть ли более эффективный способ выполнить несколько JOIN и объединить результаты, или есть другой подход к этой проблеме?
ИЗМЕНЕНО ДЛЯ ДОБАВЛЕНИЯ:
Barmar имеет правильный ответ на мой вопрос, но моим следующим шагом было расширение предложения where для возврата нескольких строк. Ссылаясь на этот вопрос , мой код в итоге выглядел так:
SELECT items.*,
(SELECT GROUP_CONCAT(related1_id) FROM item_has_related_1 WHERE item_id = items.id) as related1Ids,
(SELECT GROUP_CONCAT(related2_id) FROM item_has_related_2 WHERE item_id = items.id) as related2Ids,
...
FROM items
WHERE <where criteria>