Question

I have the following query as below.

SELECT Day(vehicleTrip.startDateTime) As day, 
       Month(vehicleTrip.startDateTime) As month,
       Sum(TIMESTAMPDIFF(SECOND, startDateTime, endDateTime )) As totalDuration,
       count(vehicleTrip.startDateTime) As totalTrip, 
       sum(endMileage-startMileage) As totalMleage
FROM vehicleTrip                            
WHERE vehicleTrip.vehicleID=:vehicleID
  AND vehicleTrip.vehicleEndCodeID!=1
  AND vehicleTrip.startDateTime BETWEEN :startDateTime And :endDateTime                             
Group By Day(vehicleTrip.startDateTime),Month(vehicleTrip.startDateTime)

Currently it works fine cause it can group by the daily date the sum of duration, totalTrip, totalMileage etc. But only issue I want the date to be arrange by desc. I have tried putting the order by startDateTime desc it gives me error that its not in GROUP By clause and containts nonaggregated column. I have tried many method like even putting the Max(vehicleTrip.startDateTime) still the same. How best can I resolve this ?

Below is my table design with its index.

CREATE TABLE `vehicleTrip` (
  `vehicleEndCodeID` tinyint NOT NULL DEFAULT '1',
  `vehicleID` mediumint NOT NULL,
  `startDateTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `endDateTime` timestamp NULL DEFAULT NULL,
  `startMileage` float(11,3) DEFAULT NULL,
  `endMileage` float(11,3) DEFAULT NULL,
  `startLatitude` float(10,8) NOT NULL,
  `startLongitude` float(11,8) NOT NULL,
  `endLatitude` float(10,8) DEFAULT NULL,
  `endLongitude` float(11,8) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;


ALTER TABLE `vehicleTrip`
  ADD PRIMARY KEY (`vehicleID`,`startDateTime`) USING BTREE;
COMMIT;
Was it helpful?

Solution

Perhaps this is what you are looking for?

SELECT Day(startDateTime) As "day", 
       Month(startDateTime) As "month",
       Sum(TIMESTAMPDIFF(SECOND, startDateTime, endDateTime ))
             As totalDuration,
       count(*) As trips, 
       sum(endMileage-startMileage) As totalMleage
FROM vehicleTrip                            
WHERE vehicleID = :vehicleID
  AND vehicleEndCodeID != 1
  AND startDateTime BETWEEN :startDateTime And :endDateTime                             
Group By 2, 1
ORDER BY 2 DESC, 1 DESC

(I'm assuming you want to sort by both month and day, latest first?)

Also consider

GROUP BY DATE(startDateTime)
ORDER BY DATE(startDateTime) DESC

More

!= is hard to optimize. I don't see any way to avoid the 'filesort', but this index might help with performance:

INDEX(vehicleID, startDateTime)   -- in this order

However, since that is already the PRIMARY KEY, do not add this INDEX.

Starting over

Now that the CREATE TABLE has been added (and this is why I ask for such so often), here is how I would answer the question:

When possible, have the same ORDER BY as GROUP BY. This allows the Optimizer to both at the same time. In your question, you did not quite have the same stuff in each.

A variation on such is to change the direction:

GROUP BY a     , b
ORDER BY a DESC, b DESC

is also optimal.

(Not relevant here:) In most cases, any mixture of ASC and DESC on the columns in ORDER BY prevents any optimization of the ORDER BY.

My suggestion of using DATE(..) instead of the two columns avoids the issue and solves the potential bug that will show up next January. BUT... It may run into the "only full group by" issues since DAY(..), MONTH(..) is not recognized as a subset of `DATE(..)

To avoid some of the above mess, I started by suggesting

GROUP BY 2     , 1
ORDER BY 2 DESC, 1 DESC

If this fails, I will pull a subquery out of my sleeve.

Licensed under: CC-BY-SA with attribution
Not affiliated with dba.stackexchange
scroll top