Я пытаюсь собрать "подписчиков" для конкретного пользователя (№1 в этом коде).
Я делаю свой основной выбор от followers
поскольку following
столбец будет содержать пользователя # 1, а followers.userid будет иметь идентификатор пользователя, делающего следующее.
Затем я пытаюсь получить количество записей из experiences
который имеет идентификатор пользователя для последователя (сколько опыта у этого последователя?)
Затем последователь будет оценивать каждый опыт (1-5 звезд), и я хочу суммировать эти рейтинги (experience.stars), чтобы получить средний рейтинг всех переживаний.
Наконец, я хочу присоединиться к записи пользовательских подписчиков из таблицы пользователей.
Я должен закончить с помощью userid, jobs, stars, * от пользователей
SELECT * FROM followers AS F
RIGHT JOIN
(SELECT count(id) FROM experiences AS M WHERE M.userid = F.userid) AS jobs
RIGHT JOIN
(SELECT sum(stars) FROM experiences AS S WHERE S.userid = F.userid) AS stars
RIGHT JOIN
users AS U ON U.userid = F.userid
WHERE F.following = 1 /* #1 = the user # I want the follwers of/for */
Я также пробовал:
SELECT * FROM followers AS F,
(SELECT count(id) FROM experiences AS M WHERE M.userid = F.userid) AS jobs,
(SELECT sum(stars) FROM experiences AS S WHERE S.userid = F.userid) AS stars
RIGHT JOIN
users AS U ON U.userid = F.userid
WHERE F.following = 1 /* #1 = the user # I want the follwers of/for */
В cPanel я получаю сообщение об ошибке, что у меня есть синтаксическая ошибка в WHERE F.userid в обоих операторах.
A) что мне не хватает, и B) есть ли лучший способ сделать это?
Мне кажется, запрос будет проще следовать так:
SELECT *
FROM followers AS F
LEFT JOIN users AS U ON U.userid = F.userid
LEFT JOIN (SELECT count(id) FROM experiences AS M WHERE M.userid = **F.userid)** AS jobs
LEFT JOIN (SELECT sum(stars) FROM experiences AS S WHERE S.userid = F.userid) AS stars
WHERE F.following = 1 /* #1 = the user # I want the follwers of/for */
;
Все те ПРАВИЛЬНЫЕ СОБЫТИЯ, которые вы изначально имели, дали бы вам только последователей, которые имели "типы" переживаний.
Кроме того, коррелированные подзапросы могут быть дорогими (и вам не нужны два из них... на самом деле вам даже не нужны подзапросы), поэтому я бы тоже переработал их так...
SELECT F.*, U.*, count(x.id), sum(x.stars)
FROM followers AS F
LEFT JOIN users AS U ON U.userid = F.userid
LEFT JOIN experiences AS x ON F.userid = x.user_id
WHERE F.following = 1
GROUP BY [all the fields selected in F and U, or just F.userid if server settings allow]
;
ON 1= 1
к каждому соединению; но тебе, наверное, лучше пойти со вторым предложением. Если вам нужно заниматься хакерскими вещами, такими как ON 1=1
, это обычно «плохая форма».
Кажется, что пара предложений ON
отсутствует.
Я знаю, что RIGHT
внешние соединения поддерживаются, но зачем нам писать так, а не писать как LEFT
внешние соединения. (Мы, как правило, резервируем RIGHT
присоединяемся к башням академических кругов.)
И это хорошо прошло время, чтобы отколоть синтаксис синтаксиса старой школы для операций объединения. (Да, он по-прежнему поддерживается для обратной совместимости с существующими операторами, но новая разработка должна использовать новый синтаксис JOIN
.)
Условие, требующее не-NULL значение F.following
, фактически отрицает "изящество" соединения, делая его эквивалентным соединению INNER. Для ясности мы должны либо написать, что как внутренний JOIN, либо если мы хотим внешнее соединение, мы должны перенести это условие в соответствующее предложение ON
.
Кроме того, наилучшей практикой является определение всех ссылок на колонки; даже если они не являются двусмысленными для оптимизатора, это упрощает работу с будущим читателем (поэтому будущему читателю не нужно проверять, какая таблица содержит столбец id
), а также защищает запрос от металирования "неоднозначного столбца", ошибки в будущем, если столбец с именем id
добавлен в другую таблицу, используемую запросом.
Кроме того, он недействителен для ссылки на столбцы из F
во внешнем запросе внутри запросов встроенного представления. Мы можем использовать коррелированный подзапрос, но не как встроенное представление.
Спецификация не ясна. Примеры данных и выборки ожидаемого результата будут иметь большое значение для разъяснения требований.
Если мы хотим использовать коррелированные подзапросы, которые возвращают одну строку, с одним столбцом, мы можем поместить их в список SELECT...
SELECT f.*
, u.*
, ( SELECT COUNT(m.id)
FROM experiences m
WHERE m.userid = f.userid
) AS jobs
, ( SELECT SUM(s.stars)
FROM experiences s
WHERE s.userid = f.userid
) AS stars
FROM followers f
LEFT
JOIN users u
ON u.userid = f.userid
WHERE f.following = 1 /* #1 = the user # I want the follwers of/for */
ORDER BY ...
Мы могли бы получить эквивалентный результат, используя встроенные представления, но это выглядело бы совсем по-другому.
Я хотел бы сделать агрегацию внутри встроенного представления, что-то вроде этого:
SELECT f.*
, u.*
, IFNULL(e.jobs,0) AS jobs
, IFNULL(e.stars,0) AS stars
FROM followers f
LEFT
JOIN users u
ON u.userid = f.userid
LEFT
JOIN ( SELECT ef.userid
, COUNT(ee.id) AS jobs
, SUM(ee.stars) AS stars
FROM followers ef
JOIN experiences ee
ON ee.userid = ef.userid
WHERE ef.following = 1 /* argument */
GROUP BY ef.userid
) e
ON e.userid = f.userid
WHERE f.following = 1 /* argument */
ORDER BY ...
RIGHT JOIN
? В этом нет ничего плохого; Я просто редко вижу, как это используется в хорошо составленных запросах.