Правильное использование UNION в SQL - PullRequest
0 голосов
/ 14 мая 2018

Мне нужно вычислить разницу между двумя различными средними значениями рейтинга: один для рейтинга фильмов до определенного года_обрезания (1980) и второй после года_обрезания, запрашивая из двух разных баз данных: Рейтинг и фильмы.

То, что я сделал, это:

Мне нужно вычислить разницу средних звезд между фильмами до 1980 года и после 1980 года.

Сначала я сгруппировал названия фильмов и вычислил средний рейтинг для каждой группы.

Во-вторых, я разделил эти группы на две категории: до 1980 года и после 1980 года

Наконец, я пытаюсь пересчитать среднее (среднее) для каждой из этих двух групп, а именно avgBefore и avgAfter, и вычислить разницу этих двух новых средних

Я ожидаю одно число, которое является avgBefore - avgAfter (avgB - avgA)

Ниже моя попытка кода. Моя главная проблема - правильно вставить два условия «до» и «после» 1980 года. Я пытаюсь определить псевдонимы, такие как avgB и avgA, но, очевидно, предложение UNION не вызывается должным образом.

SELECT AVG(avgB) - AVG(avgA)
FROM(
SELECT AVG(stars) as avgB
FROM Rating
JOIN Movie
ON Rating.mID = Movie.mID 
GROUP BY title
HAVING year < 1980
UNION
SELECT AVG(stars) as avgA
FROM Rating
JOIN Movie
ON Rating.mID = Movie.mID 
GROUP BY title
HAVING year > 1980
);

Ответы [ 6 ]

0 голосов
/ 14 мая 2018

Сначала вы хотите получить среднюю оценку за фильм.Из этого результата вы хотите получить средний рейтинг фильмов как до 1980 года, так и после 1980 года.Отсюда два шага: агрегация на фильм, затем общая агрегация.

select
  avg(r.stars) as total,
  avg(case when m.year < 1980 then r.stars end) as pre1980,
  avg(case when m.year > 1980 then r.stars end) as post1980,
  avg(case when m.year < 1980 then r.stars end) -
  avg(case when m.year > 1980 then r.stars end) as diff
from
(
  select mid, avg(stars) as stars
  from rating
  group by mid
) r
join movie m on m.mid = r.mid;

(Как уже упоминалось, вы можете включить 1980 фильмов в диапазон до или после и не опускать их полностью).

0 голосов
/ 14 мая 2018

Наиболее эффективный способ сделать это использует условное агрегирование:

SELECT (AVG(CASE WHEN m.year < 1980 THEN r.stars END) -
        AVG(CASE WHEN m.year >= 1980 THEN r.stars END)
       ) AS averag
FROM Rating r JOIN
     Movie m
     ON r.mID = m.mID;

Попытка использовать два отдельных запроса только усложняет запрос, чем он должен быть.

0 голосов
/ 14 мая 2018

Вы делаете это неправильно.В UNION не может быть двух разных псевдонимов.Ваш скрипт знает только о псевдониме avgB.Вместо UNION я предлагаю вам использовать JOIN.

0 голосов
/ 14 мая 2018

Используйте объединение вместо UNION:

SELECT 
    AVG(avgB) - AVG(avgA)
FROM
(
    (
        SELECT
            AVG(stars) as avgB
        FROM 
            Rating
        JOIN 
            Movie
        ON 
            Rating.mID = Movie.mID 
        WHERE 
            year < 1980
    ) t1
    CROSS JOIN
    (
        SELECT
            AVG(stars) as avgA
        FROM 
            Rating
        JOIN 
            Movie
        ON 
            Rating.mID = Movie.mID 
        WHERE 
            year < 1980
    ) t2
);
0 голосов
/ 14 мая 2018

Что если мы будем следовать этому подходу:

SELECT 
    (AVG(CASE WHEN year < 1980 THEN stars ELSE 0 END)-
    AVG(CASE WHEN year >= 1980 THEN stars ELSE 0 END)) AS averag
FROM Rating
JOIN Movie ON Rating.mID = Movie.mID
0 голосов
/ 14 мая 2018

Попробуйте:

SELECT AVG(avgB) - AVG(avgA)
  FROM(
       SELECT AVG(stars) as avgB
         FROM Rating
         JOIN Movie
         ON Rating.mID = Movie.mID 
        WHERE Movie.year < 1980
       GROUP BY title
      UNION
       SELECT AVG(stars) as avgA
         FROM Rating
         JOIN Movie
         ON Rating.mID = Movie.mID 
        WHERE Movie.year >= 1980
       GROUP BY title
      );

ПРИМЕЧАНИЕ : Я не знаю, откуда вы получаете значение year, поэтому вам нужно будет его указать.

ОБНОВЛЕНИЕ : исправлена ​​ссылка на year.

ОБНОВЛЕНО 2 : исправлен запрос.

Вот что я нашел.Обратите внимание, что сейчас у меня нет доступа к БД для проверки синтаксиса, но я думаю, это должно быть в основном ОК:

SELECT (AVG(B.Rating_OLD) - AVG(B.Rating_NEW)) AS Rating_Diff
  FROM (
        SELECT A.title , AVG(A.stars_OLD) AS Rating_OLD ,AVG(A.stars_NEW) AS Rating_NEW
          FROM (
                SELECT title                                    , 
                       CASE 
                          WHEN Movie.year <  1980 THEN Rating.stars
                          ELSE                         0
                       END AS stars_OLD                         ,
                       CASE 
                          WHEN Movie.year >= 1980 THEN Rating.stars
                          ELSE                         0
                       END AS stars_NEW                         
                  FROM Rating
                  JOIN Movie
                   ON Rating.mID = Movie.mID
               ) A
         GROUP BY A.title 
       ) B
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...