这个标题不太合理,所以我会尽力解释。
我在一个表中有一个非常大的数据集(1000行)。本表中的数据与车辆的全球定位系统跟踪有关。当车辆处于静止状态(Speed=0)时,在12小时内,纬度和经度会发生很大的变化。
我当前的SELECT查询如下:
$query = "SELECT UUID, UNITID, Truncate(LONGITUDE,6) AS LONGITUDE, Truncate(LATITUDE,6) AS LATITUDE, SPEED, TRACKINGTIME FROM trackpoint_au WHERE SPEED > -1 Order By UnitID, TRACKINGTIME";查询通过PHP返回一个XML页面。像这样建造的:
header("Content-type: text/xml");
// Start XML file, echo parent node
echo '<markers>';
// Iterate through the rows, printing XML nodes for each
while ($row = @mysql_fetch_assoc($result)){
// ADD TO XML DOCUMENT NODE
echo '<marker ';
echo 'unitid="' . $row['UNITID'] . '" ';
echo 'lat="' . $row['LATITUDE'] . '" ';
echo 'lng="' . $row['LONGITUDE'] . '" ';
echo 'spd="' . $row['SPEED'] . '" ';
echo 'time="' . $row['TRACKINGTIME'] . '" ';
echo '/>';
}
// End XML file
echo '</markers>';输出结果如下:
<marker unitid="7711010426" lat="-32.080402" lng="115.854890" spd="0" time="2011-11-30 06:15:00" />
<marker unitid="7711010426" lat="-32.080376" lng="115.854880" spd="0" time="2011-11-30 06:16:00" />
<marker unitid="7711010426" lat="-32.080364" lng="115.854880" spd="0" time="2011-11-30 06:17:00" />
<marker unitid="7711010426" lat="-32.080330" lng="115.854836" spd="0" time="2011-11-30 06:18:00" />
<marker unitid="7711010426" lat="-32.080326" lng="115.854860" spd="1.85" time="2011-11-30 06:20:00" />
<marker unitid="7711010426" lat="-32.080265" lng="115.854890" spd="0" time="2011-11-30 06:21:00" />
<marker unitid="7711010426" lat="-32.080276" lng="115.854920" spd="0" time="2011-11-30 06:22:00" />
<marker unitid="7711010426" lat="-32.080315" lng="115.854900" spd="0" time="2011-11-30 06:23:00" />
<marker unitid="7711010426" lat="-32.080296" lng="115.854866" spd="0" time="2011-11-30 06:24:00" />我的问题是:如何使用PHP或MYSQL返回spd=0?行的平均纬度/经度。
我得到的数据应该如下所示:
<marker unitid="7711010426" lat="-32.080367" lng="115.8548715" spd="0" time="2011-11-30 06:18:00" />
<marker unitid="7711010426" lat="-32.080326" lng="115.854860" spd="1.85" time="2011-11-30 06:20:00" />
<marker unitid="7711010426" lat="-32.080288" lng="115.854894" spd="0" time="2011-11-30 06:24:00" />注意,“平均”行有最后一个平均行的时间戳。
我试过用“按速度分组”。但是,这不能满足我的需要,因为它以相同的速度对所有记录进行分组,而不仅仅是那些值为0的记录。
编辑
按照macek的建议,按UUID进行分组没有帮助,因为UUID对于每一行都是唯一的。
<marker time="2011-11-30 06:15:00" spd="0" lng="115.854890" lat="-32.080402" unitid="7711010426" uuid="c6d50454-aa5b-4069-8756-72c787923173"/>
<marker time="2011-11-30 06:16:00" spd="0" lng="115.854880" lat="-32.080376" unitid="7711010426" uuid="be6f9052-ab00-430a-8cec-6abf5051cad1"/>答案
在发布了这个问题并阅读了下面的一些答案之后,我成功地将这些PHP代码放在了一起。它遍历所有行,检查速度,如果速度为0,检查下一行(直到speed<>0),并将这些点的lat/lng平均值。
for($i=0;$i<$num;$i++){
mysql_data_seek($result,$i);
$row = mysql_fetch_assoc($result);
if ($row['SPEED']==0){
//echo $i . ' spd: '.$row['SPEED'] . '<br />';
$spd0 = true;
$counter = 1;
$lat = $row['LATITUDE'];
$lng = $row['LONGITUDE'];
$i++;
while (($spd0==true) && ($i<$num)){
//echo ' + ' . $i;
mysql_data_seek($result,$i);
$row2 = mysql_fetch_assoc($result);
if (($row2['UNITID']==$row['UNITID']) && ($row2['SPEED']==0)){
$counter++;
$lat = $lat + $row2['LATITUDE'];
$lng = $lng + $row2['LONGITUDE'];
//echo $i . ' spd: '.$row2['SPEED'] . '<br />';
$i++;
}
else{
$spd0=false;
$i--;
}
}
$lat = $lat/$counter;
$lng = $lng/$counter;
// ADD TO XML DOCUMENT NODE
echo '<marker ';
echo 'uuid ="' . $row['UUID'] . '" ';
echo 'unitid="' . $row['UNITID'] . '" ';
echo 'lat="' . $lat . '" ';
echo 'lng="' . $lng . '" ';
echo 'spd="' . $row['SPEED'] . '" ';
echo 'time="' . $row['TRACKINGTIME'] . '" ';
echo '/>';
}
else {
//echo $i;
// ADD TO XML DOCUMENT NODE
echo '<marker ';
echo 'uuid ="' . $row['UUID'] . '" ';
echo 'unitid="' . $row['UNITID'] . '" ';
echo 'lat="' . $row['LATITUDE'] . '" ';
echo 'lng="' . $row['LONGITUDE'] . '" ';
echo 'spd="' . $row['SPEED'] . '" ';
echo 'time="' . $row['TRACKINGTIME'] . '" ';
echo '/>';
}
} 如果有人有一种更优雅的方式检查下一行,请发布它,一如既往地寻找改进我的代码的方法。
谢谢大家!
发布于 2011-12-02 08:01:25
除了GROUP BY和AVG()的正常使用之外,您可能还对Quassnoi对我的问题的回答感兴趣:
GROUP BY for continuous rows in SQL
他发布了一个非常好的解决方案,在许多行中也执行得很好。
将速度看作一个状态,您希望在一个具有相同速度的时间段内聚合所有连续行。
下面是我使用此方法重写查询的尝试:
SELECT
UNITID,
/* we aggregate multiple rows, maybe you want to know which ones..
this one is optional */
CAST(GROUP_CONCAT(UUID SEPARATOR ', ') AS CHAR) AS UUIDS,
/* is group field in the inner subquery, we can just use it
in our select without an aggregate function */
SPEED,
/* very important to select the lowest timestamp -
this is the time when your unit has stopped moving ..
first row with speed=0 */
MIN(TRACKINGTIME) AS TRACKINGTIME,
/* we calc the average on latitude here */
TRUNCATE(AVG(LATITUDE),6) AS LATITUDE,
/* same for longitude */
TRUNCATE(AVG(LONGITUDE),6) AS LONGITUDE,
/* maybe you want to know how many rows with speed 0
are grouped together */
COUNT(UUID) AS AGGREGATE_COUNT
FROM (
SELECT
/* this increases the counter variable @r each time
the state has changed.. when speed of the previous row
was also "0" and is "0" in the current row,
the counter is not increased. -- this is a virtual field
we will use for GROUPing.
@speed is used to remember the speed of the previous
row for comparison in @r to determine if the speed has changed
*/
@r := @r + (@prev_unit != UNITID
OR @prev_speed != 0
OR SPEED != 0) AS gn,
@prev_speed := SPEED AS a_speed,
@prev_unit := UNITID AS a_unit,
tp.*
FROM (
SELECT @r := 0,
@prev_speed := 1,
@prev_unit := ''
) vars,
trackpoint_au tp
ORDER BY
UNITID, TRACKINGTIME
) q
GROUP BY
gn
ORDER BY
UNITID测试数据:
CREATE TABLE `trackpoint_au` (
`uuid` int(11) NOT NULL AUTO_INCREMENT,
`latitude` decimal(10,0) NOT NULL,
`longitude` decimal(10,0) NOT NULL,
`speed` int(11) NOT NULL,
`unitid` int(11) NOT NULL,
`trackingtime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`uuid`)
) ENGINE=MyISAM;
INSERT INTO trackpoint_au (unitid, speed, latitude, longitude, trackingtime) VALUES
(1, 0, 10, 10, NOW()),
(1, 0, 20, 20, NOW()),
(1, 1, 10, 10, NOW()),
(1, 0, 10, 10, NOW()),
(1, 0, 30, 30, NOW()),
(2, 0, 10, 10, NOW()),
(2, 0, 20, 20, NOW()),
(3, 1, 10, 10, NOW()),
(4, 0, 10, 10, NOW()),
(4, 0, 20, 20, NOW()),
(4, 1, 30, 30, NOW()),
(4, 0, 60, 60, NOW()),
(4, 0, 60, 60, NOW());结果:
+--------+--------+-------+---------------------+-----------+-----------+-----------------+
| UNITID | UUIDS | SPEED | TRACKINGTIME | LATITUDE | LONGITUDE | AGGREGATE_COUNT |
+--------+--------+-------+---------------------+-----------+-----------+-----------------+
| 1 | 2, 1 | 0 | 2011-12-05 09:34:13 | 15.000000 | 15.000000 | 2 |
| 1 | 3 | 1 | 2011-12-05 09:34:13 | 10.000000 | 10.000000 | 1 |
| 1 | 4, 5 | 0 | 2011-12-05 09:34:13 | 20.000000 | 20.000000 | 2 |
| 2 | 6, 7 | 0 | 2011-12-05 09:34:13 | 15.000000 | 15.000000 | 2 |
| 3 | 8 | 1 | 2011-12-05 09:34:13 | 10.000000 | 10.000000 | 1 |
| 4 | 9, 10 | 0 | 2011-12-05 09:34:13 | 15.000000 | 15.000000 | 2 |
| 4 | 11 | 1 | 2011-12-05 09:34:13 | 30.000000 | 30.000000 | 1 |
| 4 | 12, 13 | 0 | 2011-12-05 09:34:13 | 60.000000 | 60.000000 | 2 |
+--------+--------+-------+---------------------+-----------+-----------+-----------------+发布于 2011-12-02 07:24:13
while ($row = @mysql_fetch_assoc($result)){
if( $row['SPEED']!=0){
echo 'list average';
clear list;
// ADD TO XML DOCUMENT NODE
echo '<marker ';
echo 'unitid="' . $row['UNITID'] . '" ';
echo 'lat="' . $row['LATITUDE'] . '" ';
echo 'lng="' . $row['LONGITUDE'] . '" ';
echo 'spd="' . $row['SPEED'] . '" ';
echo 'time="' . $row['TRACKINGTIME'] . '" ';
echo '/>';
} else {
//put data to a list
}
}发布于 2011-12-02 06:00:17
这会让你走上正确的轨道
-- get average lat/lng for each unitid where speed is 0
select uuid, unitid, avg(lat), avg(lng)
from trackpoint_au
where speed=0
group by uuid, unitid当使用group by时,任何没有使用复合函数的选定字段都应该添加到group by语句中。
编辑
添加uuid以选择和分组
https://stackoverflow.com/questions/8352331
复制相似问题