2017-04-01 2 views
1

J'ai un système qui permet aux utilisateurs de créer des horaires de vidéos à regarder. Le MySQL suivant tire des horaires actifs et aussi des informations sur le nombre de vidéos dans le calendrier, le nombre déjà regardé, et le nombre qui doit être regardé aujourd'hui. Il le fait via plusieurs jointures à la même table qui suit les associations de planifications-à-vidéos.Pourquoi ai-je besoin de COUNT (DISTINCT ...) dans ce MySQL?

SELECT 
    schedules.*, 
    COUNT(DISTINCT sv1.vid_id) AS total_vids, #<-- the problem 
    GROUP_CONCAT(DISTINCT sv1.context_node_id) AS topics, 
    COUNT(sv2.vid_id) AS vids_watched, 
    COUNT(sv3.vid_id) AS today 
FROM schedules 
JOIN schedule_vids sv1 ON schedules.id = sv1.schedule_id 
LEFT JOIN schedule_vids sv2 ON schedules.id = sv2.schedule_id && sv2.watched IS NOT NULL 
LEFT JOIN schedule_vids sv3 ON schedules.id = sv3.schedule_id && sv3.date = CURDATE() 
WHERE user_id = ? && schedules.id = ? 
GROUP BY schedules.id 
ORDER BY created DESC 

Le problème: si je ne l'utilise COUNT (DISTINCT sv1.vid_id) (à savoir juste COUNT(sv1.vid_id)) Je reçois un nombre bien au-delà du nombre réel. J'ai vérifié cela dans la base de données. Est-ce que quelqu'un voit où je vais mal? Il est intéressant, si je supprime la jointure à sv3 (et la partie correspondante de l'instruction select, bien sûr), le problème disparaît.

[UPDATE]

est ici la structure de table pour les deux tables impliquées:

CREATE TABLE `schedules` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
`name` varchar(50) NOT NULL, 
`user_id` varchar(11) NOT NULL, 
`created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, 
`start` date NOT NULL, 
`end` date NOT NULL, 
`inc_weekends` enum('y') DEFAULT NULL, 
`type` enum('ls','c') NOT NULL DEFAULT 'ls' COMMENT 'ls = learning schedule; c = course', 
`subj_id` varchar(30) NOT NULL, 
PRIMARY KEY (`id`) 
) ENGINE=MyISAM AUTO_INCREMENT=51 DEFAULT CHARSET=latin1 

et

CREATE TABLE `schedule_vids` (
`schedule_id` int(11) NOT NULL, 
`vid_id` varchar(11) NOT NULL, 
`context_node_id` varchar(11) NOT NULL, 
`date` date NOT NULL, 
`watched` date DEFAULT NULL, 
PRIMARY KEY (`schedule_id`,`vid_id`,`context_node_id`) 
) ENGINE=MyISAM DEFAULT CHARSET=latin1 

Exemple de sortie:

id    50 
name   some-schedule 
user_id   yd8i0i63bd8 
created   2017-04-01 11:58:22 
start   2017-04-01 
end    2017-04-03 
inc_weekends y 
type   ls 
total_vids  91 
topics   maths 
vids_watched 0 
today   91 
+1

Les exemples de données et les résultats souhaités aideraient les autres à comprendre le problème. –

+0

Mise à jour ....... – Utkanos

Répondre

2

Selon toute vraisemblance, vous ne pas besoin le distinct. Le problème est vos jointures. Utilisez à la place l'agrégation conditionnelle:

SELECT s.*, 
     COUNT(*) AS total_vids, #<-- the problem 
     GROUP_CONCAT(DISTINCT sv.context_node_id) AS topics, -- distinct is probably still needed here 
     COUNT(watched) AS vids_watched, 
     SUM(sv.date = CURDATE()) AS today 
FROM schedules s JOIN 
    schedule_vids sv 
    ON s.id = sv.schedule_id LEFT JOIN 
    school_users su 
    ON s.user_id = su.uid -- I'm guessing `user_id` comes from s 
WHERE s.user_id = ? AND s.id = ? 
GROUP BY s.id 
ORDER BY s.created DESC; 

Si vous exécutez votre requête sans l'agrégation, vous verrez ce qui se passe. Vous obtenez un produit cartésien de vidéos, c'est pourquoi les comptes sont désactivés.

+0

Merci pour votre aide. Cependant, je reçois la "colonne inconnue 'sv3.date' dans 'liste de champs'" - ne peut pas voir où vous définissez 'sv3' comme je l'ai fait, ou étais-je censé remplir ce bit dedans? – Utkanos

+0

Et quelle est la raison de 'SUM()' plutôt que 'COUNT()'? – Utkanos

+1

Je pense que le sv3 devrait juste être sv, il a été laissé par accident. –