Можно ли обрабатывать SELECT, SELECT COUNT и перекрестные таблицы ссылок только одним запросом?

У меня есть страница, которая отображает список проектов. В каждом проекте отображаются следующие данные, извлеченные из базы данных mysqli:

  1. заглавие
  2. подзаголовок
  3. Описание
  4. Номер детали (1 x)
  5. Общее количество фотографий, связанных с этим проектом
  6. Случайно выбранная фотография из проекта
  7. Список тегов

Проекты отображаются 6 страниц с использованием системы разбиения на страницы

Поскольку это основано на моем старом проекте, он был изначально выполнен с неаккуратным кодом (я просто учился и не знал ничего лучшего), используя много запросов. Три, фактически, только для пунктов 5-7, и они содержались внутри цикла while, который работал с системой разбиения на страницы. Теперь я прекрасно понимаю, что это даже близко к тому, чтобы быть правильным способом заниматься бизнесом.

Я знаком с INNER JOIN и использованием подзапросов, но я обеспокоен тем, что я не могу получить все эти данные, используя только один запрос выбора по следующим причинам:

  • Элементы 1-4 достаточно просты с базовым запросом SELECT , НО …

  • Пункт 5 нуждается в SELECT COUNT AND …

  • Пункт 6 требует базового запроса SELECT с ORDER by RAND LIMIT 1 чтобы выбрать одно случайное фото из всех, связанных с каждым проектом (с использованием FilesystemIterator не может быть и речи, потому что в таблице фотографий есть столбец, указывающий 0, если фотография неактивна и 1, если он активен)

  • Пункт 7 выбирается из таблицы перекрестных ссылок для тегов и проектов и таблицы, содержащей идентификатор и имена тегов

Учитывая это, я не уверен, что все это может (даже если это важно) выполнить только с одним запросом или если потребуется несколько запросов. Я неоднократно читал, как стоит писать на носу газету, чтобы вложить один или несколько запросов внутри цикла while. Я даже читал, что несколько запросов – это, в общем, плохая идея.

Поэтому я застрял. Я понимаю, что это может показаться слишком общим, но у меня нет никакого кода, который работает, а только старый код, который использует 4 запроса для выполнения задания, 3 из которых вложены в цикл while.

Структура базы данных ниже.

Таблица проектов:

 +-------------+---------+----------+---------------+------+ | project_id | title | subtitle | description | part | |---------------------------------------------------------| | 1 | Chevy | Engine | Modify | 1 | | 2 | Ford | Trans | Rebuild | 1 | | 3 | Mopar | Diff | Swap | 1 | +-------------+---------+----------+---------------+------+ 

Фотографий таблица:

 +----------+------------+--------+ | photo_id | project_id | active | |--------------------------------| | 1 | 1 | 1 | | 2 | 1 | 1 | | 3 | 1 | 1 | | 4 | 2 | 1 | | 5 | 2 | 1 | | 6 | 2 | 1 | | 7 | 3 | 1 | | 8 | 3 | 1 | | 9 | 3 | 1 | +----------+------------+--------+ 

Таблица тегов:

 +--------+------------------+ | tag_id | tag | |---------------------------| | 1 | classic | | 2 | new car | | 3 | truck | | 4 | performance | | 5 | easy | | 6 | difficult | | 7 | hard | | 8 | oem | | 9 | aftermarket | +--------+------------------+ 

Таблица перекрестных ссылок тегов / проектов:

 +------------+-----------+ | project_id | tag_id | |------------------------| | 1 | 1 | | 1 | 3 | | 1 | 4 | | 2 | 2 | | 2 | 5 | | 3 | 6 | | 3 | 9 | +------------+-----------+ 

Я не прошу, чтобы код был написан для меня, но если то, что я прошу, имеет смысл, я искренне ценю толкание в правильном направлении. Часто я борюсь с руководствами PHP и MySQLi в Интернете, поэтому, если есть способ разбить это, то фантастический.

Большое спасибо всем вам.

Вы можете делать подзапросы внутри предложения SELECT , например:

 SELECT p.title, p.subtitle, p.description, p.part, (SELECT COUNT(photo_id) FROM Photos where project_id = p.project_id) as total_photos, (SELECT photo_id FROM Photos where project_id = p.project_id ORDER BY RAND LIMIT 1) as random_photo FROM projects as p 

Теперь, для списка тегов, поскольку он возвращает более одной строки, вы не можете сделать подзапрос, и вы должны сделать один запрос для каждого проекта. Ну, на самом деле вы можете, если вы вернете все теги в какой-то конкатенации, например, в список с разделителями-запятыми: tag1, tag2, tag3 … но я не рекомендую в этот раз вам разбить значение столбца , Делайте это только в том случае, если у вас много проектов, а производительность для получения списка тегов для каждого отдельного проекта довольно низкая. Если вы действительно этого хотите, вы можете:

 SELECT p.title, p.subtitle, p.description, p.part, (SELECT COUNT(photo_id) FROM Photos where project_id = p.project_id) as total_photos, (SELECT photo_id FROM Photos where project_id = p.project_id ORDER BY RAND LIMIT 1) as random_photo, (SELECT GROUP_CONCAT(tag SEPARATOR ', ') FROM tags WHERE tag_id in (SELECT tag_id FROM tagproject WHERE project_id = p.project_id)) as tags FROM projects as p 

Как вы сказали из пункта 1 – 4, у вас уже есть решение.

Добавьте к тому же запросу SQL_CALC_FOUND_ROWS вместо SELECT COUNT чтобы решить элемент 5.

Для элемента 6 вы можете использовать подзапрос или, возможно, LEFT JOIN ограничивающий один результат.

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