En esencia el problema es simple. El tema se resuelve exactamente como lo planteas, pero en el area de SQL la lógica graficada se representa exactamente al reves: La selección "gruesa" es la interna y los datos buscados están en el exterior.
Me explico:
Se trata de una consulta a tres niveles, lo que vulgarmente se denomina "consulta anidadas" y se hace realizando las etapas de a una desde la más gruesa a la mas fina (interior-> exterior).
Lo importante es lo siguiente: Cada consulta crea una tabla virtual en memoria, por lo que para que un dato que se usa en la externa exista, debe ser derivado a ella desde la interna. Esto significa que el campo "referido" debe ser parte de la consulta más gruesa, aunque en esa consulta no signifique nada.
Esto sería:
Código sql:
Ver originalSELECT usuario_id, referido, COUNT(*) compras
FROM usuario LEFT JOIN compra USING(usuario_id)
GROUP BY usuario_id;
Sabemos que esto genera una sumatoria de las compras realizadas por cada usuario. Si lo que deseamos es la suma total de compras por referidos, pero con subtotales, debemos hacer una subconsulta:
Código sql:
Ver originalSELECT referido, usuario_id, nombres, apellidos, SUM(compras) TotalCompras
FROM
(SELECT usuario_id, referido,nombres, apellidos, COUNT(*) compras
FROM usuario LEFT JOIN compra USING(usuario_id)
GROUP BY usuario_id) t1
GROUP BY referido WITH ROLLUP;
Esto debe devolver la suma parcial de cada uno, además de una línea con el total. Si le quitas el WITH ROLLUP, solamente te devolverá el valor de la suma total, pero para eso tines otra consulta, que hace todo:
Código sql:
Ver originalSELECT usuario_id, referido, COUNT(*) compras
FROM usuario LEFT JOIN compra USING(usuario_id)
GROUP BY referido;
Nota que con sólo cambiar el campo de agrupamiento tienes la suma que necesitas... sin más trámite.
Si cambias LEFT JOIN por INNER JOIN, te devolverá solamente los usuarios que hayan sido referidos por alguien. COmo por ejemplo, todos los referidos a "juan", pero no las compras hechas por "juan", si juan no tiene un referido.
Aquí lo único que debes establecer es el nivel de desagregación que necesitas obtener.