6

Relacionada ¿Como agrupar un registro que se repite, mostrando todos registros distintos que se le asocien?

Estoy haciendo una consulta para obtener todos los clientes y el total de cuentas asociadas pero no quiero mostrar los que ya tengo asociados.

Tengo las siguientes tablas:

----dbClientes-----    --------syUsers--------    -----syUsers_WebAccess----
|  id  |  Nombre  |    |  id  |  Nombre      |    | id | idUser | idClient |
-------------------    -----------------------    --------------------------
|  1   |  Juan    |    |  1   | Contabilidad |    | 1  |    1   |    1     |
|  2   |  Victor  |    |  2   | JuankGlezz   |    | 2  |    1   |    3     |
|  3   |  Arturo  |    -----------------------    | 3  |    2   |    1     |
-------------------                               --------------------------

Haciendo la siguiente consulta me trae todos los clientes con el total de cuentas asociadas.

SELECT DISTINCT C.Nombre, C.id, IFNULL(NC.NumCuentas,0) AS NumCuentas
FROM dbclientes C
LEFT JOIN (
    SELECT idClient, count(id) AS NumCuentas FROM syUsers_WebAccess
  ) NC ON NC.idCliente = C.id

Me arroja como resultado:

Nombre   idCliente  NumCuentas
Juan        1          2
Victor      2          1
Arturo      3          0

Ahora quiero aplicar Obtener todos los clientes Excepto los clientes que tiene asociado JuankGlezz, es decir espero como resultado esto:

Nombre   idCliente  NumCuentas
Victor      2          1
Arturo      3          0

En caso de que el usuario seleccionado fuera Contabilidad se mostraria lo siguiente:

Nombre   idCliente  NumCuentas
Victor      2          1

¿Como seria la consulta para obtener esos resultados?, intente con esto, pero solo funciona si solo hay una cuenta asociada.

SELECT * FROM (
    SELECT DISTINCT C.Nombre, C.id, IFNULL(NC.NumCuentas,0) AS NumCuentas
    FROM dbclientes C
    LEFT JOIN (
        SELECT idCliente, count(id) AS NumCuentas FROM syUsers_WebAccess
      ) NC ON NC.idCliente = C.id
) TB
WHERE id != (SELECT idCliente FROM syUsers_WebAccess WHERE idUser = 48)

Nota: No puedo simplemente poner el idClient, debido a que desde la aplicación obtengo solo el idUser

JuankGlezz
  • 5,398
  • 8
  • 28
  • 57

2 Answers2

6

Lo más simple para esto es usar NOT EXISTS:

SELECT DISTINCT C.Nombre, C.id, IFNULL(NC.NumCuentas,0) AS NumCuentas
FROM dbclientes C
LEFT JOIN ( SELECT  idClient, 
                    count(id) AS NumCuentas 
            FROM syUsers_WebAccess
            GROUP BY idClient) NC 
    ON NC.idCliente = C.id
WHERE NOT EXISTS(SELECT 1 FROM syUsers_WebAccess
                 WHERE idUser = 2 --JuanKGlezz
                 AND idCliente = NC.idCliente)
;

Acá hay una demo de esto.

Lamak
  • 7,971
  • 14
  • 24
  • [Encontré esta respuesta](https://stackoverflow.com/a/2246793/3791844) (un poco vieja ya) donde se dice que `In MySQL, NOT EXISTS is a little bit less efficient`, pero no estoy seguro de que aún aplique – Marcos Aug 25 '17 at 16:37
1

Otra solución es hacer un LEFT JOIN a la table sysUsers_WebAcces y excluir todos los clientes donde el idUser = 2

Así por ejemplo:

SELECT C.Nombre, C.id, SUM(IF(ISNULL(NC.id), 0, 1)) AS NumCuentas
FROM dbClientes C
  LEFT JOIN syUsers_WebAccess AS NC
    ON NC.idCliente = C.id
WHERE C.id NOT IN (
  SELECT idCliente 
  FROM syUsers_WebAccess 
  WHERE idUser = 2)
GROUP BY C.id

Demo

PD: Podrías reemplazar el NOT IN por el NOT EXISTS de la respuesta de @Lamak

Marcos
  • 30,626
  • 6
  • 28
  • 63