嘿伙计们我有下表:
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
有什么类似的吗?
答案 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