2010-07-22 3 views
17

J'ai deux tables. Je veux les joindre d'une manière qu'un seul enregistrement dans la bonne table est retourné pour chaque enregistrement dans le tableau le plus à gauche. J'ai inclus un exemple ci-dessous. Je voudrais éviter les sous-requêtes et les tables temporaires car les données réelles sont d'environ 4 millions de lignes. Je ne me soucie pas non plus de savoir quel enregistrement de la table la plus à droite correspond, tant que l'un ou l'autre n'a pas de correspondance. Merci!Aide à la requête MySQL JOIN: retourne une seule ligne de la table la plus à droite pour chaque ligne de la table la plus à gauche

utilisateurs de table:

------------- 
| id | name | 
------------- 
| 1 | mike | 
| 2 | john | 
| 3 | bill | 
------------- 

transactions de table:

--------------- 
| uid | spent | 
--------------- 
| 1 | 5.00 | 
| 1 | 5.00 | 
| 2 | 5.00 | 
| 3 | 5.00 | 
| 3 | 10.00 | 
--------------- 

résultat attendu:

--------------------- 
| id | name | spent | 
--------------------- 
| 1 | mike | 5.00 | 
| 2 | john | 5.00 | 
| 3 | bill | 5.00 | 
--------------------- 
+0

Pourquoi tout le monde est-il groupé par user.id (une clé primaire) et user.name? Une fois que vous avez groupé par une clé primaire, vous n'avez vraiment besoin d'rien d'autre. Ai-je raté quelque chose, ou est-ce que nous ne faisons que copier @OMG Poneys? – TheJacobTaylor

+2

@TheJacobTaylor: SQL standard requiert que vous incluiez les colonnes non agrégées dans GROUP BY. Le standard ANSI supporte le fait de ne pas définir toutes les colonnes s'il y a un sous-groupe inutile - MySQL supporte cela, mais cela ne fonctionnera pas sur la plupart des autres bases de données. –

+2

@TheJacobTaylor: MySQL ne nécessite pas toutes les colonnes de regroupement; presque tous les autres SGBD, ainsi que le standard SQL. –

Répondre

33

Utilisation:

SELECT u.id, 
     u.name, 
     MIN(t.spent) AS spent 
    FROM USERS u 
    JOIN TRANSACTIONS t ON t.uid = u.id 
GROUP BY u.id, u.name 

Notez que cela ne retournera que les utilisateurs qui ont au moins un enregistrement TRANSACTIONS. Si vous voulez voir les utilisateurs qui ne disposent pas de soutien des dossiers ainsi que ceux qui font usage -:

SELECT u.id, 
      u.name, 
      COALESCE(MIN(t.spent), 0) AS spent 
    FROM USERS u 
LEFT JOIN TRANSACTIONS t ON t.uid = u.id 
GROUP BY u.id, u.name 
+0

+1 gentil, je luttais pour trouver une solution – northpole

+0

Ah! Bien sûr. Parfois, je deviens si myope. Une question mise à part, n'y avait-il pas un JOIN dans les versions antérieures de MySQL qui l'a naturellement fait? –

+0

Oui, cela s'appelle une jointure à gauche. :) La jointure droite forcera un match. Les jointures à gauche incluront des correspondances sans les nécessiter. – TheJacobTaylor

2

Si vous ne se soucient pas de la ligne particulière que vous obtenez en retour.

select id, name, spent 
from users 
left join transactions on users.id = transactions.uid 
group by id 

Cela retournera une ligne par utilisateur. Ce sera la première transaction correspondante.

Cheers, Jacob

0

Mes excuses si cela ne répond pas vraiment à votre question. Il semble que vous essayez de voir quels utilisateurs ont au moins une transaction. Vous pouvez le faire et dans le processus de voir combien chaque utilisateur a passé en faisant quelque chose comme ceci:

 
SELECT 
    u.id, 
    u.name, 
    SUM(t.spent) AS total 
FROM 
    USERS u 
    INNER JOIN TRANSACTIONS t 
     ON t.uid = u.id 
GROUP BY 
    u.id 
    , u.name 
+0

Ils indiquent spécifiquement dans la question un ou aucun correspond à la fois bien. – TheJacobTaylor

+0

Oups, mon erreur. Je l'ai lu comme "un ou plusieurs" – wshato

1

Voir SO 3305709 pour un équivalent question récente, avec un certain nombre de réponses raisonnables. Le SGBD cité ici est Postgres, mais les différences ici sont négligeables.

+1

'DISTINCT ON' est seulement supporté par Postgres, et DISTINCT retournerait plusieurs lignes avec des valeurs distinctes' spent' par utilisateur. –

Questions connexes