获取每个truckId的GPS数据(lat,lon,地址)和最新的时间日期

时间:2013-01-14 07:03:19

标签: mysql sql

嘿伙计们我有下表:

  

main(rowId,posDatetime,truckId,lat,lon,address)

rowId:PK
posDatetime:坐标和地址的日期和时间
truckId
纬度,经度
地址:地址字符串

行不按日期时间顺序提供。

通过此查询FOR EACH卡车

获取每辆卡车的最新位置
  

SELECT * FROM main WHERE truckId = XXXX ORDER BY posDatetime DESC LIMIT 1

它让我得到了我想要的东西,但我觉得它效率低下,我尝试过使用MAX(),但它获取的数据行不是具有MAX()值的数据。

有没有办法做类似的事情:

  

从main中选择*,其中rowId = MAX(posDatetime).rowID GROUP BY truckId

有什么类似的吗?

3 个答案:

答案 0 :(得分:1)

一种解决方案,很快就会给卡车最后说明的位置。 另一种解决方案是将两列posDateTime和mainId添加到卡车工作台并更改触发器中的逻辑。

该解决方案假设您有一个支持触发器的mysql版本。

-- drop table if exists last_position_for_truck ;

CREATE TABLE if not exists `last_position_for_truck` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `truckId` int(11) unsigned NOT NULL,
  `mainId` int(11) unsigned NOT NULL,
  `posDateTime` datetime NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `truckId` (`truckId`)
) ENGINE=myisam DEFAULT CHARSET=latin1;

-- make sure there is a one to one relationship with trucks and last_position_for_truck
-- can be run multiple times
-- must be run if a new truck is added if nothing else is done to maintain the one to one relationship
insert into `last_position_for_truck` ( truckId, mainId, posDateTime )
select truckId, mainId, posDateTime from (
    select truck.id truckId, 0 mainId,  DATE_SUB(NOW(), INTERVAL 1 YEAR) `posDateTime`
    , last_position_for_truck.id last_position_for_truck_id
    from truck
    left join last_position_for_truck
    on last_position_for_truck.truckId = truck.id
) last_position_for_truck
where last_position_for_truck_id is null ;

-- DROP TRIGGER if exists main_insert_trigger ;

delimiter $$
CREATE TRIGGER main_insert_trigger AFTER insert ON main
  FOR EACH ROW BEGIN
    update last_position_for_truck 
    set posDateTime = new.posDateTime 
    , mainId = new.id
    where truckId = NEW.truckId and posDateTime < NEW.posDateTime ;
  END$$
delimiter ;

-- assume there is a truck id of 1 and 2, -35.8739731, 152.22774 is somewhere in Asutralia
insert into main( truckId, posDateTime, lat, lon, address ) values ( 2, now(), -35.8739731, 152.22774, 'Somewhere in Australia' ) ;
insert into main( truckId, posDateTime, lat, lon, address ) values ( 1, now(), -35.8739731, 152.22774, 'Somewhere in Australia' ) ;

-- see the results
select last_position_for_truck.truckId 
, last_position_for_truck.mainId
, main.lat
, main.lon
, main.`posDateTime`
from last_position_for_truck 
left join main
on main.id = last_position_for_truck.mainId
where last_position_for_truck.id in (1,2) ;

-- sample results
1   14  -35.874 152.228 2013-01-15 11:00:18
2   13  -35.874 152.228 2013-01-15 10:59:33

答案 1 :(得分:0)

据我所知,您的原始版本与您的查询一样高效。但是,您可以在posDatetime上创建一个索引,这将大大加快您的查询速度,而不是让数据库做这么多工作。

答案 2 :(得分:0)

您可以在truckId和posDatetime上添加组合键以进行限制,仅在posDatetime上添加一个用于排序。

ALTER TABLE main
    ADD KEY 'main_cIdx_truckId_posDatetime' ( truckId, posDatetime ),
    ADD KEY 'main_idx_posDatetime' ( posDatetime );

如果您正在按其他行排序(您说的是主体),请尝试在此行上添加键。

确保rowId是主键。 如果按时间顺序插入数据,请按rowId而不是posDatetime排序。

为了加快订购速度,您可以预先选择一个时间窗口。例如如果一辆卡车肯定在路上每月一次,你可以将结果限制在一个月的时间窗口:

WHERE 
    truckId = n 
    AND
    posDatetime > DATE_SUB ( CURENT_DATE, INTERVAL 30 DAY )
ORDER BY
    rowId DESC
LIMIT 1