2011-07-05 6 views
2

J'essaie de trouver le nombre de crédits vidéo d'un utilisateur particulier.Requête COUNT compliquée dans MySQL

Voici les trois tableaux qui sont pertinents:

CREATE TABLE `userprofile_userprofile` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `full_name` varchar(100) NOT NULL, 
    ... 
) 

CREATE TABLE `userprofile_videoinfo` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `title` varchar(256) NOT NULL, 
    `uploaded_by_id` int(11) NOT NULL, 
    ... 
    KEY `userprofile_videoinfo_e43a31e7` (`uploaded_by_id`), 
    CONSTRAINT `uploaded_by_id_refs_id_492ba9396be0968c` FOREIGN KEY (`uploaded_by_id`) REFERENCES `userprofile_userprofile` (`id`) 
) 

CREATE TABLE `userprofile_videocredit` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `video_id` int(11) NOT NULL, 
    `profile_id` int(11) DEFAULT NULL, 
    KEY `userprofile_videocredit_fa26288c` (`video_id`), 
    KEY `userprofile_videocredit_141c6eec` (`profile_id`), 
    CONSTRAINT `profile_id_refs_id_31fc4a6405dffd9f` FOREIGN KEY (`profile_id`) REFERENCES `userprofile_userprofile` (`id`), 
    CONSTRAINT `video_id_refs_id_4dcff2eeed362a80` FOREIGN KEY (`video_id`) REFERENCES `userprofile_videoinfo` (`id`) 
) 

Le tableau est videoinfo lorsqu'un utilisateur télécharge une vidéo, il recevra une liste de « uploaded_by ». Le tableau videocredit sont tous les crédits pour un film donné. Il est totalement indépendant du téléchargement du film (c'est-à-dire qu'une vidéo peut être téléchargée par un utilisateur sans se créditer, et un utilisateur peut être crédité dans une vidéo qu'il n'a pas téléchargée).

En essayant de trouver le comte de vidéos d'un utilisateur a été crédité dans, je veux trouver:

# videos a user has uploaded + # of non duplicate-video credits uploaded by others 

A titre d'exemple: si un utilisateur télécharge 5 vidéos appelé:

VideoME1, VideoME2, VideoME3, VideoME4, and VideoME5 
(total = 5 videos [`videoinfo.uploaded_by_id`]) 

et a les crédits vidéo suivants:

VideoME1 (4 credits - director, writer, editor, choreographer) 
VideoME2 (1 credit) 
VideoOTHER1 (2 credits - writer, editor) 
VideoOTHER2 (1 credit - writer) 
(total = 8 video credits [`videocredit.profile_id`]) 

Le COUNT doit être 5 (vidéos mises en ligne) + 2 (non DUPLICAT e crédits de vidéo mises en ligne par d'autres) = 7. Si un utilisateur n'a pas de crédits vidéo, il doit = ​​0 (à savoir LEFT OUTER JOIN).

Je suis en mesure de comprendre les CHEFS pour chacun des uploads/crédits, mais ne peut pas comprendre comment combiner les deux et se débarrasser des doublons. De quel SQL ai-je besoin pour faire ça? Je vous remercie.

D'ailleurs, c'est ce que j'ai actuellement pour chaque (individuel) COUNT:

mysql> SELECT full_name, v.video_id, COUNT(DISTINCT v.video_id) as cnt 
    -> FROM userprofile_userprofile u LEFT OUTER JOIN userprofile_videocredit v 
    -> ON u.id = V.profile_id 
    -> GROUP BY full_name 
    -> ORDER BY cnt DESC; 

mysql> SELECT full_name, v.id, COUNT(v.uploaded_by_id) as cnt 
    -> FROM userprofile_userprofile u LEFT OUTER JOIN userprofile_videoinfo v 
    -> ON u.id = v.uploaded_by_id 
    -> GROUP BY full_name 
    -> ORDER BY cnt DESC; 

Répondre

2

La suggestion de X-Zero d'ajouter un "crédit de téléchargement" aux données est le meilleur moyen de garder la requête simple. Si ce n'est pas une option, faire une jointure entre userprofile_videoinfo et userprofile_videocredit pour le rendre facile à éliminer les doublons:

SELECT u.id, u.full_name, COUNT(DISTINCT v.video_id) as credit_count 
FROM userprofile_userprofile u 
LEFT JOIN (SELECT vi.video_id, vi.uploaded_by_id, vc.profile_id as credited_to_id 
    FROM userprofile_videoinfo vi 
    JOIN userprofile_videocredit vc ON vi.id = vc.video_id 
    ) v ON u.id = v.uploaded_by_id OR u.id = v.credited_to_id 
GROUP BY u.id, u.full_name 
ORDER BY credit_count DESC 

Le sous-requête peut être utile de créer une vue.

+0

super, un type:' vi.video_id' devrait être 'v.id' (il y en a deux cas, L1 et L3). Je vais mettre en place une nouvelle colonne pour count, mais je voulais juste voir comment faire cette requête SQL particulière Merci – David542

+0

+1, merci de m'avoir fait réfléchir davantage sur ce qui était vraiment demandé –

+0

typo * pas de type. – David542

1

Il y a essentiellement 2 façons de le faire:
1) Ajouter « Uploader » comme quelque chose qu'ils peuvent être crédité pour et ajouter un déclencheur pour remplir automatiquement l'entrée - une seule table pour aller, etc.
2) Je crois que la requête suivante devrait également fonctionner (qui sera également prendre soin de votre problème full_name):

WITH credit_rollup (profile_id) as (SELECT profile_id 
            FROM userprofile_videocredit 
            GROUP BY profile_id, video_id) 
SELECT full_name, COALESCE((SELECT count(*) 
          FROM credit_rollup as v 
          WHERE v.profile_id = u.id), 0) + 
        COALESCE((SELECT count(*) 
          FROM userprofile_videoinfo as v 
          WHERE v.uploaded_by_id = u.id), 0) as credits 
FROM userprofile_userprofile 
ORDER by credits DESC 

Bien que, vous pouvez supprimer « userprofile » de devant chaque nom de la table, et il suffit de les mettre dans un schéma avec ce nom.


La requête éditée ne comptait que 1 crédit par vidéo.


Après avoir examiné le poste une fois de plus, il est devenu évident que j'ai raté une utilisation clé du mot « double » - en ce que l'utilisateur a été QU'A fois pour télécharger la vidéo et ayant une sorte de crédit dans la vidéo (directeur, éditeur, etc.), mais pas deux fois (qui est un OU).
En tant que tel, la requête suivante est plus en ligne (et grâce à @simon me fait penser à ce sujet):

WITH credit_rollup (uploaded_by_id, credited_to_id) 
        AS (SELECT info.uploaded_by_id, credit.profile_id 
         FROM userprofile_videoinfo as info 
         JOIN userprofile_videocredit as credit 
         ON info.id = credit.video_id 
         GROUP BY info.uploaded_by_id, credit.profile_id) 
SELECT usr.full_name, COALSECE((SELECT count(*) 
           FROM credit_rollup as rollup 
           WHERE rollup.uploaded_by_id = usr.id 
           OR rollup.credited_to_id = usr.id), 0) as credits 
FROM userprofile as usr 
ORDER BY credits DESC 

Comme @simon dit, le CTE (il a utilisé un sous-requête) peut être utile créer une vue (essentiellement, il énumère tout le monde une fois pour leur implication dans une vidéo, une chose pratique d'avoir).

+0

cela ne tient pas compte des doublons. Par exemple, si j'ai dix crédits dans une vidéo, la requête COUNT ci-dessus sera = 10 au lieu de, ce qu'elle devrait, 1. – David542

+0

merci pour l'explication. La requête ne marche pas tout à fait, mais je vais essayer de comprendre où se trouve l'erreur de syntaxe (bien que mon inclination soit liée au 'credited_to_id'.) – David542

+0

J'avais laissé la clause' FROM' dans le requête principale, et 'user' est un mot réservé ... Doh! –

0

Si je ne l'ai pas fait une erreur:

SELECT u.id 
    , u.full_name 
    , (SELECT COUNT(*) 
     FROM userprofile_videoinfo vi 
     WHERE u.id = vi.uploaded_by_id 
     ) AS cnt_VideosUploadedBy       <---- 5 
    , cnt_Credits_InMyUploads 
     + cnt_Videos_CreditedIn - cnt_Videos_CreditedIn_and_UploadBy 
     AS cnt_Difficult        <---- 5 + 4 - 2 = 7 
    , cnt_Credits_Total         <---- 8 
    , cnt_Credits_InMyUploads       <---- 5 
    , cnt_Videos_CreditedIn        <---- 4 
    , cnt_Videos_CreditedIn_and_UploadBy     <---- 2 
FROM userprofile_userprofile u 
    LEFT JOIN 
     (SELECT u.id 
      , COUNT(vc.video_id) 
       AS cnt_Credits_Total 
      , (COUNT(vi.profile) 
       AS cnt_Credits_InMyUploads 
      , COUNT(DISTINCT vc.video_id) 
       AS cnt_Videos_CreditedIn 
      , (COUNT(DISTINCT vi.id) 
       AS cnt_Videos_CreditedIn_and_UploadBy 
     FROM userprofile_userprofile u 
      JOIN userprofile_videocredit vc 
      ON u.id = vc.profile_by_id 
      LEFT JOIN userprofile_videoinfo vi 
      ON vc.video_id = vi.id 
      AND vi.profile = u.id 
     GROUP BY u.id 
    ) AS grp 
    ON grp.id = u.id