2010-07-22 26 views
17

Tengo dos tablas. Quiero unirme a ellos de forma que solo se registre un registro en la tabla correcta para cada registro en la tabla de la izquierda. He incluido un ejemplo a continuación. Me gustaría evitar las subconsultas y las tablas temporales ya que los datos reales son de 4M filas. Tampoco me importa qué registro en la tabla de la derecha coincida, siempre que coincidan uno o ninguno. ¡Gracias!Ayuda de consulta de MySQL JOIN: solo devuelve una fila de la tabla de la derecha para cada fila en la tabla de la izquierda

tabla de usuarios:

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

transacciones de mesa:

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

salida esperada:

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

¿Por qué todos se agrupan por user.id (una clave principal) y user.name? Después de agrupar por una clave principal, realmente no necesita nada más. ¿Me estoy perdiendo algo, o todos estamos copiando @OMG Ponies? – TheJacobTaylor

+2

@TheJacobTaylor: SQL estándar requiere que incluya columnas no incluidas en los agregados en GROUP BY. El estándar ANSI admite que no se definan todas las columnas si se trata de un subconjunto innecesario; MySQL lo admite, pero no funcionará en la mayoría de las demás bases de datos. –

+2

@TheJacobTaylor: MySQL no requiere todas las columnas de agrupamiento; casi todos los demás DBMS lo hacen, al igual que el estándar SQL. –

Respuesta

33

Uso:

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 

Tenga en cuenta que esto solo devolverá a los usuarios que tengan al menos un registro de TRANSACCIONES. Si desea ver los usuarios que no tienen registros de apoyo, así como aquellos que lo hacen - Uso:

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 bueno, estaba luchando por encontrar una solución – northpole

+0

¡Ah! Por supuesto. A veces me vuelvo tan miope. Una pregunta aparte, ¿no había un JOIN en versiones anteriores de MySQL que naturalmente hiciera esto? –

+0

Sí, se llama unión izquierda. :) Right join forzará un partido. Las uniones a la izquierda incluirán las coincidencias pero no las requieren. – TheJacobTaylor

2

Si no se preocupan por la fila particular que vuelvas.

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

Esto devolverá una fila por usuario. Será la primera transacción coincidente.

Saludos, Jacob

0

Mis disculpas si esto en realidad no responde a su pregunta. Parece que está intentando ver qué usuarios tienen al menos una transacción. Se podría hacer esto y en el proceso de ver la cantidad de cada usuario ha pasado haciendo algo como esto:

 
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

Específicamente afirman en la pregunta que una o ninguna coincidencia son correctas. – TheJacobTaylor

+0

Vaya, mi error. Lo leí como "uno o más" – wshato

1

Ver SO 3305709 para una reciente pregunta equivalente, con un número de respuestas razonables. El DBMS citado allí es Postgres, pero las diferencias aquí son insignificantes.

+1

"DISTINCT ON" solo es compatible con Postgres, y DISTINCT devolverá varias filas con distintos valores 'gastados' por usuario. –

Cuestiones relacionadas