2010-07-05 13 views
1

J'ai une table utilisateur (Utilisateur) et 3 tables de tutoriel (Texte, Vidéo et Autre). Chaque tutoriel a les colonnes rating_positive et rating_negative et est lié à un utilisateur (id).Comment grouper des colonnes résumées de différentes tables?

Je veux sélectionner les 10 utilisateurs avec le plus de tutoriels et la somme des évaluations positives/négatives de leurs tutoriels.

J'ai essayé la requête suivante mais cela ne fonctionne pas. Il renvoie beaucoup trop de résultats pour tutorials_count/pos/neg. Comment puis-je le faire correctement?

SELECT 
    u.id AS user_id, 
    (COUNT(t.id) + COUNT(v.id) + COUNT(o.id)) AS tutorials_count, 
    (SUM(t.rating_positive) + SUM(v.rating_positive) + SUM(o.rating_positive)) AS pos, 
    (SUM(t.rating_negative) + SUM(v.rating_negative) + SUM(o.rating_negative)) AS neg 
FROM 
    user u LEFT JOIN trick t ON u.id = t.submitter_id 
    LEFT JOIN video v ON u.id = v.submitter_id 
    LEFT JOIN other o ON u.id = o.submitter_id 
GROUP BY u.id 
ORDER BY tutorials_count DESC 
LIMIT 10 

Répondre

2

Essayez de faire une sous-requête avec UNION ALL des trois tableaux qui vous intéressent, puis se joindre à ce que:

SELECT 
    u.id AS user_id, 
    COUNT(submitter_id) AS tutorials_count, 
    IFNULL(SUM(rating_positive), 0) AS pos, 
    IFNULL(SUM(rating_negative), 0) AS neg 
FROM user u 
LEFT JOIN (
    SELECT submitter_id, rating_positive, rating_negative FROM trick 
    UNION ALL 
    SELECT submitter_id, rating_positive, rating_negative FROM video 
    UNION ALL 
    SELECT submitter_id, rating_positive, rating_negative FROM other 
) T1 
ON u.id = T1.submitter_id 
GROUP BY u.id 
ORDER BY tutorials_count DESC 
LIMIT 10 
+0

cela fonctionne. :-) Y a-t-il encore une meilleure requête avec une performance plus rapide? – Smock

1

La gauche JOIN sont très bien, et interprétera mieux que unioning trois tables avant d'effectuer l'agrégation. Le problème est que SUMmation sur un LEFT JOIN signifie que le résultat pourrait être NULL, que vous ne pouvez pas ajouter en conjonction avec la somme des autres colonnes. IE:

... SUM(t.rating_positive) + 1 

... retourne NULL si SUM(t.rating_positive) il n'y a pas de support des documents, car NULL + 1 est égal à NULL.

Vous devez utiliser COALESCE pour convertir ceux-ci à zéro pour le calcul au travail - IFNULL est une alternative acceptable, mais il est spécifique MySQL donc pas susceptible d'être portable:

SELECT u.id AS user_id, 
      COALESCE(COUNT(t.id), 0) + COALESCE(COUNT(v.id), 0) + COALESCE(COUNT(o.id), 0) AS tutorials_count, 
      COALESCE(SUM(t.rating_positive), 0) + COALESCE(SUM(v.rating_positive), 0) + COALESCE(SUM(o.rating_positive), 0) AS pos, 
      COALESCE(SUM(t.rating_negative), 0) + COALESCE(SUM(v.rating_negative), 0) + COALESCE(SUM(o.rating_negative), 0) AS neg 
    FROM USER u 
LEFT JOIN trick t ON u.id = t.submitter_id 
LEFT JOIN video v ON u.id = v.submitter_id 
LEFT JOIN other o ON u.id = o.submitter_id 
GROUP BY u.id 
ORDER BY tutorials_count DESC 
    LIMIT 10 
+0

Ceci retourne les mêmes (mauvaises) valeurs que sans les COALESCEs – Smock

+0

Ceci et la version UNION sont équivalents - l'UNION s'arrête juste d'avoir à attraper des NULL sur une base par table donc la seule possibilité que je peux venir est que vous avez simplifié la requête détails et ne peut pas concilier ceux avec la requête que j'ai fournie. –

Questions connexes