2012-05-14 11 views
8

Una descarga se compone de tiempos de descarga, id de tiempo de descarga e ID de buno. Las fallas se componen de códigos de falla, id de tiempo de descarga, estado y tipo. Una descarga puede tener muchas fallas y se puede unir en la id del tiempo de descarga.Unir a la izquierda en Postgres Valores no devueltos para nulo

Dado un conjunto de códigos de falla, los resultados deben contener cada código de falla con un conteo de fallas correspondiente. Si no se encuentra un código de falla en la descarga, el código de falla se debe devolver con un recuento de fallas de cero.

El problema parece requerir un OUTER JOIN, pero no lo he visto funcionar como se esperaba en Postgres ya que no parece devolver el conjunto con valores nulos de la tabla IZQUIERDA.

La consulta está por debajo, con algunos detalles omitidos por razones de brevedad:

SELECT f.faultcode, f.downloadtimeid, d.downloadtime, count(*) as faultcount 
FROM download_time d 
LEFT OUTER JOIN fs_fault f ON f.downloadtimeid = d.id 
    AND f.faultcode IN (1000,1100) 
    AND f.statusid IN(2, 4) 
WHERE (d.downloadtime BETWEEN '04/11/2011' AND '05/01/2012') 
    AND d.bunoid = 166501 
GROUP BY d.bunoid, f.downloadtimeid, d.downloadtime, f.faultcode 

Al día siguiente, he editado para mostrar la respuesta. Todas las respuestas fueron cercanas y tuvieron varios elementos de asistencia. Sin embargo, la respuesta de JayC fue la más cercana. Aquí es el SQL final, con el único cambio que la cláusula WHERE de tomar la culpa de código EN declaración:

SELECT f.faultcode, f.downloadtimeid, d.downloadtime, count(*) as faultcount 
FROM download_time d 
RIGHT OUTER JOIN fs_fault f ON f.downloadtimeid = d.id 
     AND f.statusid IN(2, 4) 
     AND d.downloadtime BETWEEN '04/11/2011' AND '05/01/2012' 
     AND d.bunoid = 166501 
WHERE f.faultcode IN (1000,1100) 
GROUP BY d.bunoid, f.downloadtimeid, d.downloadtime, f.faultcode 

Gracias, todos por su ayuda! Me encanta este sitio!

+1

¿Ha analizado sus datos? Dudo que sea un problema dentro de PostgreSQL ... ¿Puedes proporcionar la estructura de la tabla y los datos de muestra en [SQL Fiddle] (http://sqlfiddle.com/), por favor? – vyegorov

+1

'download_time d UNIÓN EXTERIOR IZQUIERDA fs_fault f ON f.downloadtimeid = d.id' tiene' download_time' como la tabla de la izquierda, no 'fs_fault'. La condición de unión no tiene nada que ver con qué tabla es izquierda o derecha en la unión. – JayC

Respuesta

20

Estoy dando mi respuesta porque tengo dudas significativas sobre las otras respuestas. Debes tener cuidado con los requisitos del filtro. Recuerde, la cláusula where se ejecuta después de sus uniones. Entonces, si hay algún requisito de filtro en la cláusula where que se refiere a la tabla no unida al exterior, usted (en muchas circunstancias) ha anulado su unión externa. Así que tomando su sql, parece que la solución más simple es utilizar la combinación adecuada o mover los nombres de la tabla de forma adecuada, y luego mover las condiciones de filtro fuera de la cláusula where y en la cláusula join.

SELECT f.faultcode, f.downloadtimeid, d.downloadtime, count(*) as faultcount 
FROM download_time d 
RIGHT OUTER JOIN fs_fault f ON 
    f.downloadtimeid = d.id 
    AND f.faultcode IN (1000,1100) 
    AND f.statusid IN(2, 4) 
    AND d.downloadtime BETWEEN '04/11/2011' AND '05/01/2012') 
    AND d.bunoid = 166501 
GROUP BY d.bunoid, f.downloadtimeid, d.downloadtime, f.faultcode 

Otra manera que creo que debe ser equivalente es

SELECT f.faultcode, f.downloadtimeid, d.downloadtime, count(*) as faultcount 
FROM download_time d 
RIGHT OUTER JOIN fs_fault f ON 
    f.downloadtimeid = d.id 
    AND d.downloadtime BETWEEN '04/11/2011' AND '05/01/2012') 
    AND d.bunoid = 166501 
WHERE 
    f.faultcode IN (1000,1100) 
    AND f.statusid IN(2, 4) 
GROUP BY d.bunoid, f.downloadtimeid, d.downloadtime, f.faultcode 

Como no importa dónde estrictamente los requisitos del filtro en fs_fault son. (Y su motor SQL va a cambiar eso de todos modos).

Editar: Aquí hay un SQLFiddle que demuestra el filtrado en la cláusula join contra la cláusula where.

+1

Tiene razón acerca de la cláusula 'WHERE' contra las condiciones' JOIN'. Arreglé mi respuesta en ese sentido. No creo que hayas abordado su pregunta sobre cómo obtener los códigos de falla deseados para mostrar * incluso si ninguno ocurre *, sin embargo. – kgrittn

+0

Gracias a todos: Atribuí un voto a todos los encuestados, ya que aprendí algo de cada uno. Sin embargo, JayC, el tuyo era el más cercano. El único cambio fue mover el 'f.faultcode IN (1000,1100)' a la cláusula where. Al hacerlo, se muestran los códigos de falla correctos. Gracias, JayC! – MAbraham1

+0

No pude hacer que SQLFiddle funcione. Estoy usando IE 7.0.5730.13CO, ya que estoy en el trabajo. Tendré que probarlo en casa, donde normalmente ejecuto Chrome. – MAbraham1

2

Esto requerirá un RIGHT OUTER JOIN. La combinación externa derecha incluye todos los valores de la tabla derecha, con NULL s donde no hay entrada en la tabla de la izquierda (no estoy seguro si esto funcionará con GROUP BY, aunque ...) sifs_fault fueron una tabla con todos los códigos de falla

En su caso, fs_fault parece contener todos los defectos de una descarga. ¿Podría ser este el caso del comportamiento inesperado?

1

La combinación externa izquierda selecciona todo en la primera tabla más las filas coincidentes en la segunda tabla. La primera tabla parece consistir en intentos de descarga. Por lo tanto, su resultado del "desde" incluye todos los intentos de descarga.

Pero no necesariamente contiene todos sus códigos de error. Lo que sucede es que no tiene fallas para uno o más códigos que cumplen los criterios.

Necesita una tabla que contenga todos los códigos de falla, para que esto funcione. Aquí solo creo una lista de los códigos de falla como la primera tabla. Creo que la siguiente consulta hace esto:

SELECT thefaults.faultcode, f.downloadtimeid, d.downloadtime, count(*) as faultcount 
FROM (select 1000 as faultcode union all select 1100 
    ) thefaults join 
     fs_fault f 
     on f.faultcode = thefaults.faultcode and 
     f.statusid in (2, 4) left outer join 
     download_time d 
     ON f.downloadtimeid = d.id 
WHERE (d.downloadtime BETWEEN '04/11/2011' AND '05/01/2012') AND 
     d.bunoid = 166501 
GROUP BY d.bunoid, f.downloadtimeid, d.downloadtime, f.faultcode 

admito: estoy usando la sintaxis SQL Server para crear "thefaults".

+0

Si un código de falla no tiene tiempo de descarga asociado, será filtrado por la cláusula where. – JayC

+0

Se presume que esto es lo que quiere el interrogador. –

2

Si desea conteos por faultcode, esto parece la solución más simple:

WITH fc(faultcode) AS (VALUES (1000,1100)) 
SELECT fc.faultcode, count(d.downloadtimeid) as faultcount 
    FROM fc 
    LEFT JOIN (fs_fault f ON f.faultcode = fc.faultcode 
         AND f.statusid IN(2, 4) 
    JOIN download_time d ON d.id = f.downloadtimeid 
         AND d.bunoid = 166501 
         AND d.downloadtime::date BETWEEN date '2011-04-11' 
                AND date '2011-05-01') 
    GROUP BY fc.faultcode 
    ORDER BY fc.faultcode 

Tenga en cuenta que seguía sus condiciones, donde las fallas no se cuentan si no tienen la StatusID o bunoid derecha. Temía un poco que la selección de la fecha no hubiera estado haciendo lo que pensabas, así que sugerí una alternativa. Incluso eso podría no hacer lo que quieras si estás usando TIMESTAMP WITHOUT TIME ZONE, pero esa es otra historia. También agregué una cláusula ORDER BY, ya que probablemente no desee que los resultados estén en un orden incoherente; sin esa cláusula puede o no estar en la secuencia GROUP BY, y eso podría cambiar sin previo aviso.

+0

Si un código de falla no tiene un tiempo de descarga asociado, será filtrado por la cláusula where. – JayC

+0

Vaya. Se corrigió añadiendo paréntesis para forzar el orden de evaluación de las uniones. ¡Gracias! – kgrittn

+0

@JayC hizo una buena observación acerca de la cláusula 'WHERE' contra las condiciones' JOIN' en su respuesta. Como se había escrito, si las condiciones excluían * las * filas * para un código de falla en particular, el faultocde no aparecería. Se corrigió moviendo las condiciones. – kgrittn

Cuestiones relacionadas