Mi empleador tiene un clúster de proceso por lotes que procesa los trabajos enviados por los usuarios. Cada trabajo por lotes consta de tres pasos: haciendo un pivot-table-ish JOIN en SQL
- trabajo comenzó
- trabajo terminado
- resultados reportados para el usuario
Los registros de software de administración de trabajos por lotes cuando cada uno de estos pasos suceden, y el archivo de registro consiste de una tupla con un código de identificación del empleado que envió el trabajo, qué paso ocurrió y una marca de tiempo de cuándo ocurrió. En CSV, se ve así:
ID step timestamp
-- ------ ---------
A start 3533
B start 3538
B finish 3549
C start 3551
A finish 3557
B report 3559
C finish 3602
A report 3603
B start 3611
C report 3623
B finish 3643
B report 3657
Y así sucesivamente.
Una característica adicional del conjunto de datos es que hay una coincidencia entre los empleados, pero no hay coincidencia entre los empleados; es decir, cada empleado tiene que esperar hasta que su trabajo actual haya informado antes de que comience su próximo trabajo. Así que cuando clasifico por fecha y limito los resultados a un solo empleado, los registros siempre aparecen en el orden "inicio", "final", "informe".
Quiero crear una tabla dinámica que agrupe cada trabajo en una sola fila. Así los datos anteriores se convierte en:
employee-ID started finished reported
----------- ------- -------- --------
A 3533 3557 3603
B 3538 3549 3559
B 3611 3643 3657
C 3551 3602 3623
Así, en el SQL:
SELECT
log.ID AS employee-ID,
start.timestamp AS started,
finish.timestamp AS finished,
report.timestamp AS reported
FROM
log
LEFT OUTER JOIN log start ON
log.ID = start.ID
AND start.step = 'start'
LEFT OUTER JOIN log finish ON
log.ID = finish.ID
AND finish.step = 'finish'
AND start.timestamp < finish.timestamp
LEFT OUTER JOIN log report ON
log.ID = report.ID
AND report.step = 'report'
AND finish.timestamp < report.timestamp
ORDER BY employee-ID,started,finished,reported;
hago necesita LEFT OUTER JOIN, porque yo también necesito para identificar los trabajos que se iniciaron pero no estaban terminados o informado.
Esto funciona bastante bien. Me da las filas que necesito. Pero me da muchas filas espurias, porque los JOIN coinciden con las entradas finish
y report
para futuros trabajos del mismo empleado además del trabajo actual. Por lo que el informe viene a buscar como:
employee-ID started finished reported
----------- ------- -------- --------
A 3533 3557 3603
B 3538 3549 3559
B 3538 3549 3657 <-- spurious
B 3538 3643 3657 <-- spurious
B 3611 3643 3657
C 3551 3602 3623
Es fácil reconocer las filas espurias: cada trabajo se inicia sólo una vez, por lo que teniendo en cuenta la clasificación, la fila correcta es la primera fila con un único "comenzó" valor. Estoy trabajando en torno al problema de las filas espurias en este momento en el nivel de la aplicación, omitiendo las filas espurias, pero eso parece, bueno, poco elegante. Y es costoso: algunos de estos empleados tienen docenas de trabajos enviados, por lo que actualmente, los resultados de mis consultas son aproximadamente el 15% de las entradas legítimas y el 85% espurias. Eso es un montón de tiempo perdido omitiendo entradas falsas. Sería bueno si cada trabajo tuviera una identificación única, pero simplemente no tengo esa información.
Necesito limitar de alguna manera la UNIÓN para que seleccione solo una entrada "finalizada" e "informada" para cada entrada "iniciada": la única entrada que tiene la marca de tiempo mínima mayor que la marca de tiempo del paso anterior. Intenté hacer esto utilizando una subconsulta como la tabla a la que me estaba INSCRIBIENDO, pero no pude entender cómo hacerlo sin una subconsulta correlacionada. También intenté hacerlo al usar "ID de empleado de GROUP BY, comencé", pero esto no necesariamente eligió la fila "correcta". La mayoría de las filas informadas por "GROUP BY" fueron las incorrectas.
Entonces, los gurús de SQL, ¿es posible informar solo las filas que necesito? Y si es así, ¿cómo? Estoy usando sqlite3 en este momento, pero podría transferir la base de datos a MySQL si es necesario.
que funciona perfectamente! Se ralentiza la consulta en menos del 5%, y la aplicación se ejecuta mucho más rápido ahora que no tiene que hacer el filtrado en sí. Muchas gracias. – STH