/
Procesamiento de datos

Tabla de contingencia en PHP

13. 11. 2019

Obsah článku

Una tabla de contingencia se utiliza generalmente para mostrar la relación entre dos fenómenos estadísticos. Al desarrollar una aplicación web, a menudo necesitaremos visualizar la relación de un determinado fenómeno en la base de datos con una secuencia temporal, normalmente en la administración.

Por ejemplo, tenemos una tabla de pedidos que muestra productos individuales y nos interesa saber cómo se relacionan las ventas de ciertos productos de gran volumen con el tiempo.

Para ello, sería útil una tabla como la siguiente:

Dátiles, manzanas, fresas, peras, etc.
2019-05
2019-04
2019-03
2019-02
2019-01

No hay una manera fácil de preparar los datos en este formulario en PHP, y obtenerlos directamente en este formulario directamente en SQL tampoco es elegante, porque tenemos que tener en cuenta que hay un número dinámico de columnas.

Así que tenemos que ser inteligentes al diseñar la salida de esta estructura de datos.

Serialización de datos mediante claves

Cuando construyo una tabla, a menudo utilizo la recuperación de todos los registros que cumplen una condición determinada directamente desde la base de datos, por ejemplo, datos de intervalo.

Específicamente:

SELECT *
FROM `order`
WHERE `inserted_date` <= '2019-05-01'
ORDER BY `inserted_date` DESC

La consulta recupera todas las columnas de la tabla de pedidos (order), filtrando todos los registros desde el principio de las edades hasta el 2019-05-01, devolviendo ordenados de más reciente a más antiguo.

Con una simple consulta SQL, obtenemos los datos casi al instante. La segunda característica interesante es que los índices de la base de datos pueden utilizarse de forma eficiente en la compilación de los resultados. Sin embargo, como tenemos los datos en un array plano, debemos serializarlos manualmente en una estructura de datos que pueda convertirse en una tabla contig.

Dado que una tabla de contingencia describe la relación de dos o más factores, tiene sentido utilizar una clave multidimensional. Sin embargo, dado que algunos datos pueden no existir para todas las combinaciones, es mejor serializar la clave a una sola cadena y almacenar los datos como una matriz plana.

Los datos se pueden ensamblar en una sola pasada del bucle (la variable $selection contiene la salida de la base de datos):

$data = [];
foreach ($selection as $row) {
$date = date('Y-m', $row->insertedDate); // Fecha año-mes
foreach ($row->items as $product) { // pasamos por los productos
$key = $date . '_' . $product->id;
if (isset($data[$key])) {
$data[$key]++; // existe, añadiremos otro producto
} else {
$data[$key] = 1; // no existe, empezaremos con el primer producto
}
}
}

Si estuviéramos explorando una estructura de datos más sencilla, no sería necesario un bucle interno para recorrer los productos. En este caso, toda la construcción de datos podría resolverse con un solo ciclo.

Con este enfoque, obtenemos un llamado array plano de valores que se parece a un `clave: valor', mientras que almacena información bidimensional.

La salida es entonces, por ejemplo (en Mayo 2019, un producto con ID 10 vendió 6 unidades):

$data = [
'2019-05_10' => 6,
...
];

Renderizar datos en una tabla - plantillas

Si tenemos los datos en forma de array plano, podemos renderizar toda la tabla muy fácilmente. Para ello, sólo necesitamos conocer los campos de todos los productos que nos interesan y los campos de todas las fechas para las que queremos trazar la tabla.

$products = [ ... ]; // campo del producto: id => nombre
$dates = [ ... ]; // por fecha: fecha => etiqueta
echo '<table>';
foreach ($products as $productId => $productName) {
echo '<tr>';
foreach ($dates as $date => $dateLabel) {
echo '<td>';
echo htmlspecialchars(
(string) ($data[$date . '_' . $productId] ?? '0')
);
echo '<td>';
}
echo '</tr>';
}
echo '</tabla>';

Tenga en cuenta que al navegar por los datos, busca una ocurrencia específica por el plegado de la clave de la cadena. Este enfoque nos permite restringir o ampliar la tabla renderizada de forma arbitraria en función de los datos que estemos consultando. Si los datos no existen, se evalúa el operador ternario ?? y se muestra el cero.

Podemos construir matrices de productos y fechas disponibles como parte del primer ciclo que prepara los datos. En ese momento, estaremos seguros de que sólo estamos trazando los datos que realmente existen. En este caso, es muy importante que la salida de la base de datos SQL esté ordenada por fecha de creación, ya que de lo contrario las filas pueden ser barajadas durante el renderizado final de la tabla.

Jan Barášek   Více o autorovi

Autor článku pracuje jako seniorní vývojář a software architekt v Praze. Navrhuje a spravuje velké webové aplikace, které znáte a používáte. Od roku 2009 nabral bohaté zkušenosti, které tímto webem předává dál.

Rád vám pomůžu:

Související články

1.
3.