查询SQL并格式化为CSV的有效方法

时间:2012-06-30 23:01:50

标签: php mysql

我有一个MySQL数据库,我正在保持几个不同传感器的温度读数。我最初想过使用三个不同的表来存储我的数据:

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 |
+----+-------------+-----------+-------+

我要做的是获取存储的数据并将其放入CSV文件中,以便我可以使用dygraphs Javascript library显示它。我需要将我的数据转换为这样的格式:

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
....

我开始这样做的每一种方式(使用PHP),我似乎使这过于复杂,并且必须将循环内的循环中的查询。我是否比自己需要更加努力?

大部分工作是使用查询还是使用PHP完成的?接下来,我还想添加一些代码,如果特定时间戳中缺少温度读数,将在CSV中放置NULL。

我不是在寻找一个非常具体的答案,我只是想知道我应该走哪条路。我甚至不知道如何从数据库开始格式化我的数据,或者我是否应该尝试使用不同的格式将我的信息存储在数据库中。

3 个答案:

答案 0 :(得分:2)

我会运行一个选择查询来加入这个批次。您可以使用可能没有数据的外部联接。

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

(参见:SQL Fiddle Example

这应该会给你一组结果,你可以循环。

如果您真的希望MySQL完成大部分工作,您可以将第一行更改为(我认为) SELECT data_period.ts +','+ IFNULL(dp1.data,'NULL')+','+ IFNULL(dp2.data,'NULL')+','+ IFNULL(dp3.data,'NULL')< / p>

要合成评论和答案,并将其输出到文件中:

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;

答案 1 :(得分:0)

为此,您可以使用两个SQL语句来提供外部循环和内部循环。第一个陈述

select  ts from data_points as point 
inner join data_period on data_period = data_period.id 
group by ts 
order by ts

将获取您拥有数据的日期列表。

内部循环中的第二个将获得由传感器ID排序的数据值列表 - 如果data_points中缺少值,则此列表将出错并且存在间隙;因此,如果您确实存在间隙,则可能需要执行额外步骤以获取传感器列表,然后从查询中返回的数据中填充此列表。

以下示例说明了如何继续执行此操作。

// 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";
}

答案 2 :(得分:0)

我建议事后在php中执行csv格式化。

这是我在网上找到的一个方便的功能,非常喜欢使用。如果您将SQL调用包装在一个类中,那么您可以在查询后使用此方法。 :)

注意我修改了这个给我MSSQL但很容易用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;
    }