Выбор строк из одной таблицы с использованием значений, полученных из другой таблицы MYSQL

У меня в настоящее время есть 2 таблицы mysql в моей db

Film и Film_Ratings_Report

Первичный ключ для фильма - filmid, который используется для идентификации номиналов пленки в таблице Film_Ratings_Report.

Я хотел бы знать, возможно ли его использование MYSQL-запроса только для поиска таблицы рейтингов и сбора всех идентификаторов фильмов, которые соответствуют определенным критериям, затем используйте выбранные идентификаторы, чтобы получить названия фильмов из таблицы Film. Ниже приведен запрос MYSQL Im, который не работает:

SELECT * 
FROM film 
UNION SELECT filmid 
      FROM film_rating_report 
      WHERE rating = 'GE' 
      LIMIT 0,0

Я относительно зеленый для MYSQL и буду признателен за любую помощь в этом.

Спасибо в Advance

Ответы

Ответ 1

SELECT * FROM film WHERE id IN 
  (SELECT filmid FROM film_rating_report WHERE rating = 'GE');

должен работать

Ответ 2

Кажется, вы хотите полу-соединение, например. соединение, в котором необходимы только данные из одной из двух соединенных таблиц. В этом случае все строки из film, для которых есть соответствующая строка в film_rating_report, которая имеет желаемое условие (rating = 'GE').

Это не совсем эквивалентно обычному соединению, потому что даже если во второй таблице есть 2 (или более) строки (2 оценки фильма, как с 'GE'), мы все равно хотим, чтобы фильм отображался один раз, а не дважды (или более раз), как это было бы показано с обычным соединением.

Существуют различные способы написания полусоединения и самые популярные:

  • используя EXISTS коррелированный подзапрос (@Justin answer):

    SELECT t1.* 
    FROM film t1 
    WHERE EXISTS (SELECT filmid 
                  FROM film_rating_report t2
                  WHERE t2.rating = 'GE'
                  AND t2.filmid = t1.id);
    
  • используя IN (некоррелированный) подзапрос (@SG 86 answer):
    (это следует использовать с особой осторожностью, поскольку оно может возвращать неожиданные результаты - или вообще ничего), если соединительные столбцы (два filmid в этом случае) являются Nullable)

    SELECT * 
    FROM film 
    WHERE id IN 
      ( SELECT filmid 
        FROM film_rating_report 
        WHERE rating = 'GE'
      );
    
  • используя обычный JOIN с GROUP BY, чтобы избежать дублирования строк в результатах (@Tomas ответ):
    (и обратите внимание, что это конкретное использование GROUP BY работает только в MySQL и в последних версиях Postgres, если вы когда-либо захотите написать аналогичный запрос в другой СУБД, вам нужно будет включить все столбцы: GROUP BY f.filmid, f.title, f.director, ...)

    SELECT f.*
    FROM film AS f
        JOIN film_rating_report AS frr
             ON f.filmid = frr.filmid
    WHERE frr.rating = 'GE' 
    GROUP BY f.filmid ;
    
  • Вариант ответа @Tomas'es, где GROUP BY выполняется на производной таблице, а затем JOIN:

    SELECT f.*
    FROM film AS f
        JOIN 
            ( SELECT filmid
              FROM film_rating_report
              WHERE rating = 'GE'
              GROUP BY filmid
            ) AS frr
          ON f.filmid = frr.filmid ;
    

Какой из них использовать, зависит от СУБД и конкретной версии, которую вы используете (например, IN подзапросы следует избегать в большинстве версий MySQL, поскольку они могут создавать неэффективные планы выполнения), ваши конкретные размеры таблиц, распределение, индексы и т.д.

Обычно я предпочитаю решение EXISTS, но никогда не боится сначала тестировать различные запросы с размерами таблиц, которые у вас есть или ожидаются в будущем, и попытаться найти лучшую комбинацию запросов-индексов для вашего случая.


Дополнение: если существует уникальное ограничение на комбинацию film_rating_report (filmid, rating), что означает, что ни один фильм никогда не получит два одинаковых рейтинга, или если на film_rating_report (filmid) существует еще более строгая (но более правдоподобная) привязка, что означает что каждый фильм имеет не более одного рейтинга, вы можете упростить решения JOIN (и избавиться от всех других запросов):

    SELECT f.*
    FROM film AS f
        JOIN film_rating_report AS frr
             ON f.filmid = frr.filmid
    WHERE frr.rating = 'GE' ;

Ответ 3

Предпочтительным решением для этого является использование join и не забывайте group by, чтобы у вас не было повторяющихся строк:

select film.*
from film
join film_rating_report on film.filmid = film_rating_report.filmid
        and rating = 'GE'
group by film.filmid

EDIT: как правильно отметили @ypercube, я ошибался, утверждая, что производительность соединения и группы лучше, чем использование подзапросов с exists или in - совсем наоборот.

Ответ 4

Query:

SELECT t1.* 
FROM film t1 
WHERE EXISTS (SELECT filmid 
              FROM film_rating_report t2
              WHERE t2.rating = 'GE'
              AND t2.filmid = t1.id);

Ответ 5

Я считаю, что это сработает, подумал, не зная вашу структуру БД (подумайте о том, чтобы дать SHOW CREATE TABLE на ваших таблицах), я не знаю точно:

SELECT film.*
FROM (film)
LEFT JOIN film_rating_report ON film.filmid = film_rating_report.filmid AND film_rating_report.rating = 'GE'
WHERE film_rating_report.filmid IS NOT NULL
GROUP BY film.filmid

( WHERE film_rating_report.filmid НЕ ЯВЛЯЕТСЯ NULL, чтобы предотвратить линии, у которых нет рейтинга, который вы ищете от кражи, я добавил GROUP BY в конце, потому что film_rating_report может совпадать более одного раза - не уверен, поскольку у меня есть видимость хранящихся в нем данных)