Manera eficiente de consultar SQL y formatear a CSV
Frecuentes
Visto 577 equipos
0
Tengo una base de datos MySQL en la que mantengo lecturas de temperatura de varios sensores diferentes. Inicialmente pensé en usar tres tablas diferentes para almacenar mis datos:
mysql> select * from sensor_info;
+----+------------------+------+--------+
| id | address | name | active |
+----+------------------+------+--------+
| 1 | 28D684CD02000057 | NULL | 1 |
| 2 | 28099B49030000D8 | NULL | 1 |
| 3 | 28339ACD0200004B | NULL | 1 |
+----+------------------+------+--------+
mysql> select * from data_period limit 4;
+----+---------------------+
| id | ts |
+----+---------------------+
| 1 | 2012-06-30 09:35:02 |
| 2 | 2012-06-30 09:36:22 |
| 3 | 2012-06-30 09:37:46 |
| 4 | 2012-06-30 09:40:36 |
+----+---------------------+
mysql> select * from data_points limit 4;
+----+-------------+-----------+-------+
| id | data_period | sensor_id | data |
+----+-------------+-----------+-------+
| 1 | 1 | 1 | 77.90 |
| 2 | 1 | 2 | 77.34 |
| 3 | 1 | 3 | 77.56 |
| 4 | 2 | 1 | 78.01 |
+----+-------------+-----------+-------+
Lo que estoy tratando de hacer es tomar mis datos almacenados y ponerlos en un archivo CSV para poder mostrarlos usando biblioteca javascript dygraphs. Necesito obtener mis datos en un formato como este:
date,temp1,temp2,temp3
2012-06-30 09:35:02,77.90,77.34,77.56
2012-06-30 09:36:22,78.01,77.36,77.59
....
Cada vez que empiezo a hacer esto (usando PHP), parece que lo hago demasiado complicado y tengo que poner consultas dentro de bucles dentro de bucles. ¿Estoy haciendo esto más difícil para mí de lo que necesito?
¿La mayor parte del trabajo se realizará mediante las consultas o mediante PHP? En el futuro, también querré agregar un código que colocará NULL en el CSV si falta una lectura de temperatura de una marca de tiempo en particular.
No estoy buscando una respuesta muy específica, solo quiero saber en qué dirección debo ir. Ni siquiera sé cómo comenzar a formatear mis datos desde la base de datos o si debería intentar buscar un formato diferente para almacenar mi información en la base de datos.
3 Respuestas
2
Ejecutaría una sola consulta de selección para unir el lote. Puede usar una unión externa donde es posible que no haya datos.
SELECT data_period.ts AS date, dp1.data AS temp1, dp2.data AS temp2, dp3.data AS temp3
FROM data_period
LEFT OUTER JOIN data_points AS dp1 ON dp1.data_period=data_period.id AND dp1.sensor_id=1
LEFT OUTER JOIN data_points AS dp2 ON dp2.data_period=data_period.id AND dp2.sensor_id=2
LEFT OUTER JOIN data_points AS dp3 ON dp3.data_period=data_period.id AND dp3.sensor_id=3
(Ver: Ejemplo de violín SQL )
Eso debería darle un conjunto único de resultados que puede recorrer.
Si realmente quiere que MySQL haga la mayor parte del trabajo, puede cambiar la primera línea a (creo) SELECT data_period.ts +','+ IFNULL(dp1.data,'NULL') +','+ IFNULL(dp2 .datos,'NULO') +','+ IFNULL(dp3.datos,'NULO')
Para sintetizar el comentario y la respuesta y obtener esto en un archivo:
SELECT data_period.ts AS date, dp1.data AS temp1, dp2.data AS temp2, dp3.data AS temp3
INTO OUTFILE '/home/user/output.csv'
FIELDS TERMINATED BY ','
OPTIONALLY ENCLOSED BY '"'
ESCAPED BY '\\'
LINES TERMINATED BY '\n'
FROM data_period LEFT OUTER JOIN data_points AS dp1 ON dp1.data_period=data_period.id
AND dp1.sensor_id=1 LEFT OUTER JOIN data_points AS dp2 ON
dp2.data_period=data_period.id AND dp2.sensor_id=2 LEFT OUTER JOIN data_points AS dp3
ON dp3.data_period=data_period.id AND dp3.sensor_id=3;
Respondido 01 Jul 12, 02:07
0
Para hacer esto, puede usar dos declaraciones SQL que proporcionen un bucle externo y otro interno. la primera declaración
select ts from data_points as point
inner join data_period on data_period = data_period.id
group by ts
order by ts
obtendrá una lista de las fechas para las que tiene datos.
El segundo en el ciclo interno obtendrá una lista de valores de datos ordenados por la identificación del sensor: si tiene valores faltantes en los puntos de datos, esta lista será incorrecta y tendrá espacios; por lo tanto, si tiene lagunas, es posible que deba realizar un paso adicional para obtener la lista de sensores y luego completar esta lista con los datos que provienen de la consulta.
El siguiente ejemplo ilustra cómo podría proceder con esto.
// get the outer list
$sql = "select ts from data_points as point
inner join data_period on data_period=data_period.id
group by ts
order by ts";
$result = mysql_query($sql);
$result || die(mysql_error());
while($row = mysql_fetch_row($result))
{
// get the date for the second query
$date = $row[0];
$sql = "select data from data_points as point
inner join data_period on data_period=data_period.id
inner join sensor_info on sensor_id = sensor_info .id
where ts = '$date'
order by sensor_id";
$result_1 = mysql_query($sql);
// now create an array from the values - we could use mysql_fetch_array to do this
// but this way allows us the possibility of extending the processing to
// take into account missing values.
$vals = array();
while($row_1 = mysql_fetch_row($result_1)) {
$vals[]=$row_1[0];
}
print "$date,".join(",",$vals)."\n";
}
Respondido 01 Jul 12, 00:07
Esto es exactamente lo que esperaba lograr. Son las consultas SQL en las que siempre me quedo atascado. Las uniones internas/uniones externas/ect son un concepto en el que me cuesta volverme bueno. - Tim XNUMX
para una buena explicación de las uniones ver codificaciónhorror.com/blog/2007/10/… - Richard Harrison
0
Recomendaría simplemente hacer el formato csv en php después del hecho.
Aquí hay una función útil que encontré en línea y realmente me encanta usar. Y si envuelve sus llamadas SQL en una clase, puede tener este método disponible después de realizar la consulta. :)
Tenga en cuenta que modifiqué esto para mí MSSQL, pero es fácil reemplazarlo solo con mysql.
public final function SQL2CSV() {
// set initial .csv file contents
$CSV = array();
$rowid = 0;
//This would be your query.
$res = $this->fetchQuery();
// get column captions and enclose them in doublequotes (") if $print_captions is not set to false
for ($i = 0; $i < mssql_num_fields($res); $i++) {
$fld = mssql_fetch_field($res, $i);
$colnames[] = $fld->name;
}
// insert column captions at the beginning of .csv file
$CSV[$rowid] = implode(",", $colnames);
// iterate through each row
// replace single double-quotes with double double-quotes
// and add values to .csv file contents
if (mssql_num_rows($res) > 0) {
while ($row = mssql_fetch_array($res, MSSQL_NUM)) {
$rowid++;
for ($i = 0; $i < sizeof($row); $i++)
//$row[$i] = '"'.str_replace('"', '""', $row[$i]).'"';
$row = str_replace (',', '', $row);
$CSV[$rowid] = "\n".implode(",", $row);
}
}
RETURN $CSV;
}
Respondido 01 Jul 12, 00:07
No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas php mysql or haz tu propia pregunta.
stackoverflow.com/questions/11198008/… - P M