Sentencia SQL para incluir filas que no tienen coincidencias en una subconsulta correlacionada

StackOverflow https://stackoverflow.com/questions/1418728

  •  07-07-2019
  •  | 
  •  

Pregunta

Tengo la subconsulta correlacionada a continuación. Cada id (147,148,149) en la tabla1 tiene muchos registros en la tabla2. Sin embargo, el id 148 no tiene registros que coincidan con la condición de tiempo en la declaración. Por lo tanto, no está incluido en la salida. Quiero que se incluya con un 0 para la columna de conteo. ¿Qué necesita ser cambiado?

SELECT b.fkid, COUNT(DISTINCT username)
FROM table2 AS b
WHERE
b.fkid IN ( 147,148,149 )
AND time > (SELECT SUBTIME(a.endTime, SEC_TO_TIME( 60*60 )) FROM table1 AS a WHERE a.id = b.fkid)
GROUP BY b.fkid

Esta declaración devuelve:

b.fkid   COUNT(DISTINCT username)
147      41
149      26

Quiero que regrese:

b.fkid   COUNT(DISTINCT username)
147      41
148       0
149      26

Bien, tengo la solución. Es una versión modificada de la respuesta de rexem:

SELECT t.fkid,
   IFNULL(nu.num_users, 0)
FROM TABLE_2 t
LEFT JOIN (SELECT t.fkid,
                  COUNT(DISTINCT t.username) 'num_users'
           FROM TABLE_2 t
           JOIN TABLE_1 a ON a.id = t.fkid
                          AND SUBTIME(a.endTime, SEC_TO_TIME( 60*60 )) < t.time
           GROUP BY t.fkid) nu ON nu.fkid = t.fkid
WHERE t.fkid IN (147, 148, 149)
GROUP BY t.fkid, nu.num_users

Changes from rexem's answer:
"SEC_TO_TIME( 60*60 )) = t.time" to "SEC_TO_TIME( 60*60 )) < t.time"
Removed "t.time" in GROUP BY clause of subquery
¿Fue útil?

Solución

Prueba:

   SELECT t.fkid,
          IFNULL(nu.num_users, 0)
     FROM TABLE_2 t
LEFT JOIN (SELECT t.fkid,
                  COUNT(DISTINCT t.username) 'num_users'
             FROM TABLE_2 t
             JOIN TABLE_1 a ON a.id = t.fkid
                           AND SUBTIME(a.endTime, SEC_TO_TIME( 60*60 )) = t.time
         GROUP BY t.fkid) nu ON nu.fkid = t.fkid
   WHERE t.fkid IN (147, 148, 149)
GROUP BY t.fkid, nu.num_users

Otros consejos

Intente usar COALESCE para manejar los escenarios en los que se compara el tiempo con el conjunto vacío (por ejemplo, porque no hay coincidencias entre la tabla1 y la tabla2):

SELECT b.fkid, COUNT(DISTINCT username)
FROM table2 AS b
WHEREb.fkid IN ( 147,148,149 )
AND time > COALESCE((SELECT SUBTIME(a.endTime, SEC_TO_TIME( 60*60 )) FROM table1 AS a WHERE a.id = b.fkid), 0)
GROUP BY b.fkid

COALESCE toma un conjunto ilimitado de parámetros y, de este grupo, devolverá el primer parámetro no nulo.

SELECT a.ID, COUNT(DISTINCT username)
FROM table1 AS a LEFT JOIN table2 AS b
on a.ID = b.fkID
WHERE a.ID IN ( 147,148,149 )
AND b.time > SUBTIME(a.endTime, SEC_TO_TIME( 60*60 )) 
GROUP BY a.ID

¿Ayuda esto de alguna manera?

EDITAR: No estoy seguro si esto puede funcionar en mysql. Pero espero que tenga la idea de construir la consulta usando esto.

Creo que su mejor oportunidad de obtener el cero en el resultado es usar una UNIÓN (disjunta). La primera parte sería su consulta actual; la segunda cláusula encontraría los valores donde no hay entradas relevantes, seleccionando la constante 0 para la columna de conteo.

A menudo, una combinación externa haría el truco. La dificultad aquí es que la unión externa produciría una fila de datos para ID = 148 y, por lo tanto, COUNT daría una respuesta de 1, no de 0.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top