2011-01-03 12 views
2

J'ai ces 3 requêtes:Comment devrais-je rejoindre ces 3 requêtes SQL dans Oracle?

SELECT 
    title, year, MovieGenres(m.mid) genres, 
    MovieDirectors(m.mid) directors, MovieWriters(m.mid) writers, 
    synopsis, poster_url 
FROM movies m 
WHERE m.mid = 1; 

SELECT AVG(rating) FROM movie_ratings WHERE mid = 1; 

SELECT COUNT(rating) FROM movie_ratings WHERE mid = 1; 

et je dois les rejoindre en une seule requête. J'ai pu le faire comme ceci:

SELECT 
    title, year, MovieGenres(m.mid) genres, 
    MovieDirectors(m.mid) directors, MovieWriters(m.mid) writers, 
    synopsis, poster_url, AVG(rating) average, COUNT(rating) count 
FROM movies m INNER JOIN movie_ratings mr 
    ON m.mid = mr.mid 
WHERE m.mid = 1 
GROUP BY 
    title, year, MovieGenres(m.mid), MovieDirectors(m.mid), 
    MovieWriters(m.mid), synopsis, poster_url; 

Mais je n'aime pas vraiment ce groupe « énorme » BY, est-il un moyen plus simple de le faire?

+1

Il est idiot de programmer selon vos préférences personnelles pour le code "bien rangé". Quand vous dites: "Je n'aime pas vraiment ce" groupe "énorme." vous ne pourriez pas sembler plus professionnel. Je ne * dis * pas que cela soit méchant de quelque façon que ce soit. D'abord, ce n'est pas énorme par aucune norme. C'est un groupe de taille très ordinaire. Deuxièmement, c'est ce que c'est. Vous devriez écrire des requêtes qui font les choses suivantes; 1. Échelle. L'activité de base de données doit bien évoluer. 2. Maintenable. Votre requête doit répondre à une norme de syntaxe et de format. –

+1

Je vous encourage fortement à éliminer les UDF. Bien qu'ils puissent rendre le SQL plus propre, ils détruisent votre évolutivité et vos performances. La règle 1 de Tom Kyte est de tout faire en SQL que vous pouvez ... quand vous NE POUVEZ PAS le faire en SQL, faites le en PL/SQL. Si le réalisateur et l'auteur ne sont que des tableaux relationnels, joignez-les tous. Si ce sont des appels SOA ou quelque chose comme ça ... alors laissez-les. –

+0

Ce que je voulais dire par là, c'est que ça n'a pas de sens pour moi et qu'il doit y avoir un meilleur moyen. Je veux dire, si je devais sélectionner un tas de champs mais pas tous (où je pourrais utiliser *) je devrais les mettre tous dans GROUP BY, cela n'a pas de sens pour moi dans le sens où je ne connais que les bases d'Oracle SQL et peut-être qu'il y a de meilleures façons de faire ce que je veux, peut-être qu'il n'y en a pas. C'est ce que le SO est pour, non? –

Répondre

5

Vous pouvez faire quelque chose comme ceci:

SELECT title 
     ,year 
     ,MovieGenres(m.mid) genres 
     ,MovieDirectors(m.mid) directors 
     ,MovieWriters(m.mid) writers 
     ,synopsis 
     ,poster_url 
     ,(select avg(mr.rating) 
     from movie_ratings mr 
     where mr.mid = m.mid) as avg_rating 
     ,(select count(rating) 
     from movie_ratings mr 
     where mr.mid = m.mid) as num_ratings 
    FROM movies m 
WHERE m.mid = 1; 

ou même

with grouped as(
    select avg(rating) as avg_rating 
     ,count(rating) as num_ratings 
    from movie_ratings 
    where mid = 1 
) 
select title 
     ,year 
     ,MovieGenres(m.mid) genres 
     ,MovieDirectors(m.mid) directors 
     ,MovieWriters(m.mid) writers 
     ,synopsis 
     ,poster_url 
     ,avg_rating 
     ,num_ratings 
    from movies m cross join grouped 
where m.mid = 1; 
+0

Ooh, mine de ferraille, j'aime ça le meilleur. – MPelletier

+0

Je n'ai jamais compris les implications et les différences entre appeler 3 requêtes SQL ou faire une seule requête SQL avec 3 SELECT comme ci-dessus ... –

+0

@Nazgulled, voulez-vous dire 3 appels de base de données distincts? – Ronnis

0

que diriez-vous

SELECT 
    title, year, MovieGenres(m.mid) genres, 
    MovieDirectors(m.mid) directors, MovieWriters(m.mid) writers, 
    synopsis, poster_url, 
    (SELECT AVG(rating) FROM movie_ratings WHERE mid = 1) av, 
    (SELECT COUNT(rating) FROM movie_ratings WHERE mid = 1) cnt 
FROM movies m 
WHERE m.mid = 1; 

ou

SELECT 
    title, year, MovieGenres(m.mid) genres, 
    MovieDirectors(m.mid) directors, MovieWriters(m.mid) writers, 
    synopsis, poster_url, 
    av.av, 
    cnt.cnt 
FROM movies m, 
    (SELECT AVG(rating) av FROM movie_ratings WHERE mid = 1) av, 
    (SELECT COUNT(rating) cnt FROM movie_ratings WHERE mid = 1) cnt 
WHERE m.mid = 1; 
2

Je suppose que je ne vois pas le problème avec plusieurs colonnes GroupBy. C'est un modèle très courant en SQL. Bien sûr, la clarté du code est souvent dans l'œil du spectateur.

Vérifiez les plans d'explication pour les deux approches; Je suppose que vous obtiendrez de meilleures performances avec votre version originale car il suffit de traiter la table movie_ratings une fois. Mais je n'ai pas vérifié, et cela dépendra des données et de l'installation.