transponer - Seleccionando filas de una tabla usando valores obtenidos de otra tabla MYSQL
seleccionar campos de una tabla mysql (5)
Consulta:
SELECT t1.*
FROM film t1
WHERE EXISTS (SELECT filmid
FROM film_rating_report t2
WHERE t2.rating = ''GE''
AND t2.filmid = t1.id);
Actualmente tengo 2 tablas mysql en mi base de datos
Film
and Film_Ratings_Report
La clave principal de Film es filmid
que se utiliza para identificar las calificaciones de la película en la tabla Film_Ratings_Report
.
Me gustaría saber si es posible usar una consulta MYSQL solo para buscar en la tabla de clasificación y recopilar todas las ID de película que cumplan con ciertos criterios y luego usar las ID seleccionadas para obtener los títulos de la película. A continuación se muestra la consulta MYSQL que estoy usando y que no funciona:
SELECT *
FROM film
UNION SELECT filmid
FROM film_rating_report
WHERE rating = ''GE''
LIMIT 0,0
Soy relativamente verde para MYSQL y agradecería cualquier ayuda en esto.
Gracias por adelantado
Creo que esto funcionará, pensé sin conocer su estructura de base de datos (considere dar SHOW CREATE TABLE en sus tablas), no tengo forma de saberlo con seguridad:
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
(El WHERE film_rating_report.filmid IS NOT NULL evita que las líneas que no tienen la calificación que está buscando se coló, agregué GROUP BY al final porque film_rating_report puede coincidir más de una vez; no estoy seguro, ya que tengo visibilidad de los datos almacenados. en eso)
La solución preferida para esto es usar join
y no olvide group by
para que no tenga líneas duplicadas:
select film.*
from film
join film_rating_report on film.filmid = film_rating_report.filmid
and rating = ''GE''
group by film.filmid
EDITAR: según lo señalado correctamente por @ypercube, me equivoqué al afirmar que el rendimiento de join & group es mejor que usar subconsultas con exists
o in
todo lo contrario.
Parece que desea una semi-join , por ejemplo, una unión donde solo se necesitan datos de una de las 2 tablas unidas. En este caso, todas las filas de la film
para las que hay una fila coincidente en film_rating_report
que tiene la condición deseada ( rating = ''GE''
).
Esto no es exactamente equivalente a una combinación habitual porque incluso si hay 2 (o más) filas en la segunda tabla (2 clasificaciones de una película, ambas con ''GE''
), queremos que la película se muestre una vez, no dos veces (o más veces) como se mostraría con una combinación habitual.
Hay varias formas de escribir una semi-unión y las más populares son:
utilizando una subconsulta correlacionada
EXISTS
( la respuesta de @Justin ):SELECT t1.* FROM film t1 WHERE EXISTS (SELECT filmid FROM film_rating_report t2 WHERE t2.rating = ''GE'' AND t2.filmid = t1.id);
utilizando una subconsulta
IN
(no correlacionada) ( respuesta de @SG 86 ):
(esto debe usarse con sumo cuidado, ya que puede generar resultados inesperados, o ninguno en absoluto, si las columnas que se unen (las dosfilmid
en este caso) son Nullable)SELECT * FROM film WHERE id IN ( SELECT filmid FROM film_rating_report WHERE rating = ''GE'' );
usando un
JOIN
habitual conGROUP BY
para evitar las filas duplicadas en los resultados ( respuesta de @Tomas ):
(y tenga en cuenta que este uso específico deGROUP BY
funciona en MySQL y en las versiones recientes de Postgres, si alguna vez desea escribir una consulta similar en otro DBMS, deberá incluir todas las columnas: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 ;
Una variación en la respuesta de @Tomas''es, donde
GROUP BY
se realiza en una tabla derivada y luego enJOIN
: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 ;
Cuál usar, depende del RDBMS y la versión específica que esté utilizando (por ejemplo, las subconsultas IN
deben evitarse en la mayoría de las versiones de MySQL, ya que pueden producir planes de ejecución ineficientes), sus tamaños de tablas, distribución, índices, etc.
Por lo general, prefiero la solución EXISTS
, pero nunca está de más probar primero las distintas consultas con los tamaños de tabla que tiene o espera tener en el futuro y tratar de encontrar la mejor combinación de índices de consulta para su caso.
Adición: si hay una restricción única en la film_rating_report (filmid, rating)
, lo que significa que ninguna película obtendrá dos calificaciones iguales, o si hay una restricción única aún más estricta (pero más plausible) en film_rating_report (filmid)
que significa que cada película tiene a lo sumo una calificación, puede simplificar las soluciones de JOIN
para (y deshacerse de todas las demás consultas):
SELECT f.*
FROM film AS f
JOIN film_rating_report AS frr
ON f.filmid = frr.filmid
WHERE frr.rating = ''GE'' ;
SELECT * FROM film WHERE id IN
(SELECT filmid FROM film_rating_report WHERE rating = ''GE'');
Deberia trabajar