ВЫБРАТЬ, 2 счета со 2-го стола, ПРАВО СОЕДИНИТЬСЯ 3

0

Я пытаюсь собрать "подписчиков" для конкретного пользователя (№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) есть ли лучший способ сделать это?

  • 0
    По какой-то конкретной причине вы используете RIGHT JOIN ? В этом нет ничего плохого; Я просто редко вижу, как это используется в хорошо составленных запросах.
  • 0
    Нет реальной причины. Я отредактировал свой вопрос и показал другой запрос, который я пробовал. Тот же результат. За исключением того, что F.userid находится в SELECT с COUNT ()
Показать ещё 1 комментарий
Теги:
count
right-join

2 ответа

1
Лучший ответ

Мне кажется, запрос будет проще следовать так:

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]
;
  • 0
    Извините за медленный ответ ... штормы убили Интернет ... только что снова в сети. Я попробовал ваш первый запрос, и это вернуло меня к тому, с чего я начал: Синтаксическая ошибка в WHERE F.following = 1; Мне придется распаковать второй и убедиться, что я полностью понимаю, прежде чем я попробую.
  • 0
    О, я вижу, похоже, что ответ Спенсера уловил проблему с первым (отсутствует в предложениях) .... похоже, что внешние соединения требуют их; если вы все еще хотите использовать первую версию (ближайшую к своей), вы можете просто добавить ON 1= 1 к каждому соединению; но тебе, наверное, лучше пойти со вторым предложением. Если вам нужно заниматься хакерскими вещами, такими как ON 1=1 , это обычно «плохая форма».
Показать ещё 1 комментарий
0

Кажется, что пара предложений 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 ...
  • 0
    Спасибо за отличный ответ, Спенсер. Распаковав вашу, я многому научился. Я отдал победу Ууэрдо только потому, что его запрос выполнялся быстрее и на самом деле мне было легче понять (хотя это было второстепенное определение). Его запрос выполняется за 0,0012 секунды до ваших 0,0017 секунд.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню