Pregunta

Necesito consultar esta base de datos para obtener cada fila, pero también la SUMA de uno de los valores de columna de los resultados. Podría usar php para obtener el valor total, pero luego necesitaría ejecutar dos bucles, uno para obtener el total (que se encuentra en la parte superior por encima de los resultados). Por lo tanto, preferiría que la consulta lo captara y simplemente hiciera un & Quot; total & Quot; fila, pero la única forma en que lo hice funcionar es con una subconsulta que es esencialmente una repetición de la consulta original. ¿Hay una mejor manera?

SELECT 
CONCAT(u.firstname, ' ', u.lastname ) name, u.id, s.description, s.shiftstart, s.shiftend, 
    (SELECT 
    SUM( TIME_TO_SEC( TIMEDIFF( shiftend, shiftstart ) ) ) /3600
    FROM shifts
    WHERE id =  '$user'
    AND DATE( shiftstart )
    BETWEEN '$start'
    AND '$end') total
FROM shifts s
INNER JOIN users u ON ( s.id = u.id )
WHERE s.id = '$user'
AND DATE( shiftstart )
BETWEEN '$start'
AND '$end'
ORDER BY shiftstart

Lo anterior funciona y resulta:

name        id     description  shiftstart             shiftend               total
Joe User    joeuser    Stuff    2009-01-05 07:45:00    2009-01-05 12:15:00    39.5000
Joe User    joeuser    Stuff    2009-01-05 13:00:00    2009-01-05 17:00:00    39.5000
Joe User    joeuser    Stuff    2009-01-06 07:45:00    2009-01-06 10:45:00    39.5000
Joe User    joeuser    Stuff    2009-01-06 10:45:00    2009-01-06 12:45:00    39.5000
Joe User    joeuser    Stuff    2009-01-06 13:30:00    2009-01-06 14:30:00    39.5000
Joe User    joeuser    Stuff    2009-01-06 14:30:00    2009-01-06 17:00:00    39.5000
Joe User    joeuser    Stuff    2009-01-07 09:45:00    2009-01-07 14:00:00    39.5000
Joe User    joeuser    Stuff    2009-01-07 15:00:00    2009-01-07 17:00:00    39.5000
Joe User    joeuser    Stuff    2009-01-08 08:00:00    2009-01-08 12:15:00    39.5000
Joe User    joeuser    Stuff    2009-01-08 13:15:00    2009-01-08 17:00:00    39.5000
Joe User    joeuser    Stuff    2009-01-09 07:45:00    2009-01-09 10:45:00    39.5000
Joe User    joeuser    Stuff    2009-01-09 11:45:00    2009-01-09 15:15:00    39.5000
Joe User    joeuser    Stuff    2009-01-09 15:15:00    2009-01-09 17:00:00    39.5000

Que es lo que necesito, pero probablemente no sea la mejor manera de obtenerlo.

¿Fue útil?

Solución

MySQL admite un modificador de grupo especial llamado ROLLUP .

SELECT CONCAT(u.firstname, ' ', u.lastname ) name, u.id, 
  s.description, s.shiftstart, s.shiftend, 
  SUM( TIME_TO_SEC( TIMEDIFF( shiftend, shiftstart ) ) ) /3600 total
FROM shifts s INNER JOIN users u ON ( s.id = u.id )
WHERE s.id = ? AND DATE( shiftstart ) BETWEEN ? AND ?
GROUP BY u.id, s.shiftstart WITH ROLLUP
ORDER BY shiftstart;

Otros consejos

La mejor manera es hacer esto con código. La gente sigue insistiendo en usar SQL, que es un álgebra relacional, para realizar tareas de procedimiento. Tratar de calzar los procedimientos en SQL es siempre una mala idea, tanto en términos de complejidad como de rendimiento. Siga este consejo de un DBA profesional.

Ejecute dos consultas desde su código. Imprima primero el conjunto más grande y luego la línea total en el formato que desee. Sus consultas serán más pequeñas y simples, su rendimiento mejorará y obtendrá el resultado que desea.

Algún otro consejo: el espacio en disco es económico y la mayoría de las tablas de bases de datos se leen con mucha más frecuencia de la que se escriben. Configure un activador de inserción / actualización (si es posible en MySQL) para llenar una columna separada con campos calculados como & Quot; CONCAT(u.firstname,' ',u.lastname) & Quot; y usar eso para consultas. Las funciones por fila no son escalables y matarán el rendimiento de su DBMS a medida que crece.

Cualquier cosa puede ser mejor en comparación; la pregunta es la comparación de qué, ¿verdad?

El problema clave que indicó es que deseaba el total en la parte superior de los resultados; Crystal Reports y otras aplicaciones manejan este tipo de magia al ser un motor de 2 pasos. El primer pase obtiene los totales.

Hay compensaciones con cualquier solución. Si obtiene un & Quot; total & Quot; fila, entonces la aplicación receptora necesitará eliminarlo de los resultados o jugar algún otro truco para ocultarlo.

Una posibilidad, que puede ser una opción si no está escribiendo para un sitio web de 1 millón de visitas / hora, es simplemente hacer 2 llamadas, una para la información general, como el nombre, el tiempo TOTAL, etc. luego para los detalles ... Aparece de la consulta que está seleccionando los resultados de una sola persona.

Todos estamos para ahorrar gastos generales y ancho de banda, pero a veces, lo simple es mejor ...

EDITAR: Pax me ganó a la & "; guardar &"; botón ... jajaja ...

Use la extensión mysql proporcionada exactamente para este propósito, como se describe en la respuesta de Bill Karwin (que yo mismo he votado).

Si esto no estuviera disponible, la opción 2 sería otra instrucción SQL: SELECCIONAR SUMA ...) SQL realmente está optimizado para ser extremadamente eficiente para este tipo de cosas, en comparación con cualquier bucle de código de procedimiento que sea probable escribir.

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