2010-11-25 6 views
1

Cette question a probablement été posée plusieurs fois, par conséquent, s'il vous plaît, excusez-moi pour les doublons, mais je ne pouvais pas trouver quelque chose comme ça et je ne pouvais pas construire quelque chose de similaire vouloir réaliser.MySQL JOIN avec SUM

Par exemple, permet de dire, j'ai la structure de tableau suivant:

//tasks 
+-------+--------------+------+-----+---------+-------+ 
| Field | Type   | Null | Key | Default | Extra | 
+-------+--------------+------+-----+---------+-------+ 
| id | int(11)  | NO | P | None | AI | 
| user | int(11)  | NO |  | None |  | 
| data | varchar(200) | NO |  | None |  | 
+-------+--------------+------+-----+---------+-------+ 

//votes 
+-------+--------------+------+-----+---------+-------+ 
| Field | Type   | Null | Key | Default | Extra | 
+-------+--------------+------+-----+---------+-------+ 
| id | int(11)  | NO | P |   | AI | 
| user | int(11)  | NO |  |   |  | 
| item | int(11)  | NO |  |   |  | 
| up | tinyint(1) | NO |  | 0  |  | 
| down | tinyint(1) | NO |  | 0  |  | 
+-------+--------------+------+-----+---------+-------+ 

Avec les données suivantes:

//tasks 
+----+------+------------+ 
| id | user | data | 
+----+------+------------+ 
| 1 | 1 | something | 
| 2 | 2 | lorem ip | 
| 3 | 1 | biggy | 
+----+------+------------+ 

//votes 
+----+------+------+----+------+ 
| id | user | item | up | down | 
+----+------+------+----+------+ 
| 1 | 8 | 1 | 1 | 0 | 
| 2 | 4 | 1 | 1 | 0 | 
| 3 | 2 | 1 | 0 | 1 | 
| 4 | 2 | 2 | 1 | 0 | 
| 5 | 1 | 2 | 1 | 0 | 
+----+------+------+----+------+ 

Je veux faire quelque chose de similaire à:

SELECT r.* FROM `tasks` WHERE `user` = '1' r 
LEFT JOIN (SELECT SUM(t.up) AS up, 
        SUM(t.down) AS down 
      FROM `votes` t 
      WHERE t.item = r.id) r ON r.id = t.item 

Et oui, c'est ma requête jusqu'à présent, mais cela ne fonctionne pas, et je ne sais pas comment corriger cela.

Basiquement, je veux:

  1. Sélectionnez tout de la table tâchesuser est "x"
  2. Rejoindre chaque ligne de tâches (sélectionnées à l'étape 1) avec somme de up, somme de down à partir du tableau votesitem est égal à id de tâches

Et cela devrait produire quelque chose comme (par exemple. user = 1):

+----+------+------------+----+------+ 
| id | user | data | up | down | 
+----+------+------------+----+------+ 
| 1 | 1 | something | 3 | 1 | 
| 3 | 1 | biggy | 0 | 0 | 
+----+------+------------+----+------+ 

Eh bien, je vous espère les gars à comprendre et peut me aider.

Merci d'avance!

Répondre

4

La clause WHERE doit être inférieure aux jointures et les alias doivent être déclarés à l'aide de AS. Ceci est un (syntaxiquement) version corrigée de votre requête:

SELECT r.* 
    FROM `tasks` 
LEFT JOIN (
      SELECT SUM(t.up) AS up, 
        SUM(t.down) AS down 
       FROM `votes` AS t 
       WHERE t.item = r.id 
     ) AS r 
     ON r.id = t.item 
    WHERE `user` = '1' 

Voici comment je le ferais (non testé):

SELECT `tasks`.`id`, 
      `tasks`.`user`, 
      `tasks`.`data`, 
      `votes`.`up`, 
      `votes`.`down` 
    FROM `tasks` 
LEFT JOIN (
       SELECT `item`, 
         SUM(`up`) AS `up`, 
         SUM(`down`) AS `down` 
       FROM `votes` 
      GROUP BY `item` 
     ) AS `votes` 
     ON `votes`.`item` = `tasks`.`id` 
    WHERE `tasks`.`user` = 1 
+0

En effet, il ne fonctionne pas, voici l'erreur: '# 1054 - Unknown column 'r.id' dans « où clause'', ressemble à la ligne 'WHERE t. item = r.id'. Et pour autant que je sache, c'est le problème avec 'r' placé après le JOIN ... corrigez-moi si je me trompe, essayant juste d'apprendre de tout cela aussi. – jolt

+0

@Tom: Votre estimation est correcte. Essayez ma deuxième version. – jwueller

+0

Eh bien, puisque vous avez eu la première réponse parfaitement opérationnelle, je vous accorde le crédit, merci pour vos efforts! Et je dois dire, mon esprit est beaucoup plus clair sur ces JOINs maintenant. – jolt

2

Voyons voir je code quelque chose comme ceci:

SELECT t.id, t.user, t.data, ifnull(u.total, 0) as up, ifnull(d.total, 0) as down 
FROM 
    tasks AS t LEFT OUTER JOIN (
     SELECT item, SUM(up) AS total FROM votes GROUP BY item 
    ) AS u ON t.id = u.item LEFT OUTER JOIN (
     SELECT item, SUM(down) AS total FROM votes GROUP BY item 
    ) AS d ON t.id = u.item 
WHERE t.user = 1; 

Ensuite, pour montrer les totaux en une seule ligne, vous pouvez essayer:

SELECT t.id, t.user, t.data, 
    ifnull((SELECT SUM(up) FROM votes GROUP BY item WHERE item = t.id), 0) AS up, 
    ifnull((SELECT SUM(down) FROM votes GROUP BY item WHERE item = t.id), 0) AS down 
FROM tasks AS t 
WHERE t.user = 1; 

Ou essayez ceci:

SELECT t.id, t.user, t.data, IFNULL(tt.up, 0) AS up, IFNULL(tt.down, 0) AS down 
FROM 
    tasks AS t LEFT OUTER JOIN (
     SELECT item, SUM(up) AS up, SUM(down) AS down 
     FROM votes 
     GROUP BY item 
    ) AS tt ON t.id = tt.item 
WHERE t.user = 1 
+0

Ceci est plus proche de ce que je cherche, mais au lieu d'afficher une ligne de * tâches *, il montre une entrée en double. Un pour les votes, un pour les votes vers le bas. – jolt

+0

Eh bien ... J'ai découvert la solution pour la double entrée (GROUP BY manquant), mais il fournit des résultats incorrects pour les votes «down». – jolt

+0

Le dernier fonctionne parfaitement! D'autres 2 ont eu des problèmes. – jolt