sql >> Base de Datos >  >> RDS >> Mysql

Consulta de PHP y Mysql, use PHP para convertir filas en columnas

Es posible obtener el resultado usando una consulta SQL, pero no es trivial.

Pero antes de seguir ese camino, te recomiendo que consideres un enfoque diferente.

Dado que la consulta devuelve un conjunto de filas relativamente pequeño, en su lugar podría recuperar el conjunto de resultados completo en PHP como una matriz bidimensional.

Considere un caso bastante simple, como ilustración:

SELECT foo, fee, fi, fo, fum
  FROM mytable 
 ORDER BY foo

foo fee fi  fo  fum
--- --- --- --- ---
ABC   2   3   5   7
DEF  11  13  17  19

Podríamos hacer un fetchAll y obtener una matriz bidimensional, luego recorrer la matriz y recuperar los valores en forma de columna, en lugar de en forma de fila. Una opción es transformar la matriz que recibimos en nuevas matrices que se vean así:

bar  ABC  DEF
---  ---  ---
fee    2   11
fi     3   13
fo     5   17
fum    7   19

No es realmente necesario hacer la transformación, podrías recorrer la matriz original. Pero separar la transformación como un paso separado probablemente haría que su código fuera un poco más fácil, cuando llegue a generar la salida en la página. (Parece un problema bastante común que alguien probablemente haya escrito una función que realiza la transformación de matriz que desea. No creo que haya un PHP integrado que lo haga.

encabezados:

array { [0]=>'bar'  [1]=>'ABC'  [2]=>'DEF' }

filas:

array {
  [0]=>array { [0]=>'fee'   [1]=>'2'  [2]=>'11' }
  [1]=>array { [0]=>'fi'    [1]=>'3'  [2]=>'13' }
  [2]=>array { [0]=>'fo'    [1]=>'5'  [2]=>'17' }
  [3]=>array { [0]=>'fum'   [1]=>'7'  [2]=>'19' }
}

Para un pequeño conjunto de filas como el suyo, optaría por hacer esto en PHP en lugar de en SQL.

Pero preguntaste cómo hacerlo en SQL. Como dije antes, no es trivial.

SQL requiere que la declaración SELECT defina cada columna que se devolverá; el número y los tipos de las columnas no pueden ser dinámicos cuando se ejecuta la instrucción.

Si construimos otra consulta (aparte de la consulta original) que define las columnas y devuelve las filas que esperamos con marcadores de posición para los valores, estamos a mitad de camino. Todo lo que queda es hacer una unión externa a las filas devueltas por la consulta original y devolver condicionalmente los valores de columna en las filas correspondientes.

Este enfoque funciona si tiene un conjunto predefinido de filas y columnas que necesitamos devolver, especialmente cuando el origen de la fila original es escaso y necesitamos generar las filas "faltantes". (Por ejemplo, obtener recuentos de productos pedidos y faltan muchas filas, no hay una buena manera de generar las filas que faltan.

Por ejemplo:

SELECT r.bar
     , '' AS `ABC`
     , '' AS `DEF`
  FROM ( SELECT 'fee' AS bar
          UNION ALL SELECT 'fi'
          UNION ALL SELECT 'fo'
          UNION ALL SELECT 'fum'
       ) r
 GROUP BY r.bar

Eso devolverá:

 bar  ABC  DEF
 ---  ---  ---
 fee
 fi
 fo
 fum

Entonces, eso nos da todas las columnas definidas y todas las filas que queremos devolver. La primera columna está llena. Esa consulta realmente no necesita GROUP BY todavía, pero lo necesitaremos una vez que coincidamos con las filas del conjunto de resultados de origen "real".

El "truco" ahora es hacer coincidir las filas de nuestra fuente y devolver el valor de una columna según las condiciones apropiadas.

Lo que vamos a generar, esencialmente es un conjunto de resultados que se ve así:

bar  foo  ABC  DEF
---  ---  ---  ---
fee  ABC    2
fee  DEF        11
fi   ABC    3
fi   DEF        13
fo   ABC    5
fo   DEF        15
fum  ABC    7
fum  DEF        17

Luego vamos a "colapsar" las filas, eliminando la columna foo del conjunto de resultados y haciendo un GRUPO POR en bar . Vamos a usar una función agregada (ya sea MAX o SUM) aprovechando el manejo que hacen con valores NULL, para producir un resultado como este:

bar  foo  ABC  DEF
---  ---  ---  ---
fee         2   11
fi          3   13
fo          5   15
fum         7   17

Usando este SQL bastante difícil de manejar:

SELECT r.bar
     , MAX(CASE WHEN t.foo = 'ABC' THEN CASE r.bar 
         WHEN 'fee' THEN t.fee 
         WHEN 'fi'  THEN t.fi
         WHEN 'fo'  THEN t.fo
         WHEN 'fum' THEN t.fum
       END END) AS 'ABC'
     , MAX(CASE WHEN t.foo = 'DEF' THEN CASE r.bar 
         WHEN 'fee' THEN t.fee 
         WHEN 'fi'  THEN t.fi
         WHEN 'fo'  THEN t.fo
         WHEN 'fum' THEN t.fum
       END END) AS 'DEF'
  FROM ( SELECT 'foo' AS col
          UNION ALL SELECT 'fee'
          UNION ALL SELECT 'fi'
          UNION ALL SELECT 'fo'
          UNION ALL SELECT 'fum'
       ) r
 CROSS
  JOIN mysource t
 GROUP BY r.bar

Tenga en cuenta que mysource en la consulta anterior se puede reemplazar con una vista en línea, ajustando los paréntesis alrededor de una consulta adecuada que devuelve las filas que queremos.

La vista en línea con alias como r es nuestra fuente para devolver las filas que queremos devolver.

Las expresiones en la lista SELECT están haciendo las pruebas condicionales, para seleccionar los valores correctos para cada columna en cada fila.

Dado el patrón regular de las declaraciones CASE, es posible usar algo de SQL para ayudar a generar la consulta, pero eso debe hacerse como un paso separado. La salida de ese SQL se puede usar para ayudar a formar la consulta real que necesitamos.

En tu caso, dado que workdate es lo que desea usar para el encabezado de la columna, es probable que tenga que generarse dinámicamente. (Puede eliminar la columna de la segunda columna 'día de la semana' de la consulta de origen original y moverla a la consulta externa.

Si no supiera la workdate valores para los encabezados antes de ejecutar la consulta, luego optaría por crear una TABLA TEMPORAL y completarla con los resultados de la consulta original, y luego consultar la tabla temporal para obtener la workdate encabezados y la "primera columna" para generar las filas. Luego ejecutaría la consulta real contra la tabla temporal.

Para repetir, creo que sería mejor hacer la transformación/giro de los resultados de su consulta original en PHP, en lugar de intentar hacerlo en SQL.