I need to select the oldest(min) due datetime for each InternalOrder and then filter these against some datetime for example NOW(). As you can see in schema image, I designed the schema as one InternalOrder has multiple Deliveries and each Delivery has multiple DeliveryRev(revisions), as I need to have whole trace of inputed data. I always look at the latest revision, if that one is deleted the whole delivery should not be considered.
Table rows:
- InternalOrder: 2970
- Delivery: 3258
- DeliveryRev: 12272
I select the newest DeliveryRev via joins and filter these, which have due datetime field filled and also are not deleted.
I have working query (first one), but it is not exactly, what I need, since I can get the result with InternalOrder, which have oldest(min) due under specified threshold(not selected) and another one, which is over (in the result). In this case I do not want that InternalOrder in the result, which I solved using having instead of where, but this query is taking ages.
Am I doing something wrong with HAVING, or how can I optimize/change to get right result?
This query is fast (40ms), but not getting right result.
SELECT
s9_.internal_order_id,
MIN(s10_.due) AS minDue
FROM sales_internal_delivery s9_
LEFT JOIN sales_internal_deliveryrev s10_
ON s9_.id = s10_.delivery_id
AND (s10_.due IS NOT NULL AND s10_.deleted = 0)
LEFT JOIN sales_internal_deliveryrev s11_
ON s10_.delivery_id = s11_.delivery_id
AND s10_.timestamp < s11_.timestamp
WHERE
s11_.delivery_id IS NULL
AND s10_.due > NOW()
GROUP BY s9_.internal_order_id
ORDER BY minDue ASC
This query is slow (25s), but the result is alright.
SELECT
s9_.internal_order_id,
MIN(s10_.due) AS minDue
FROM sales_internal_delivery s9_
LEFT JOIN sales_internal_deliveryrev s10_
ON s9_.id = s10_.delivery_id
AND (s10_.due IS NOT NULL AND s10_.deleted = 0)
LEFT JOIN sales_internal_deliveryrev s11_
ON s10_.delivery_id = s11_.delivery_id
AND s10_.timestamp < s11_.timestamp
WHERE
s11_.delivery_id IS NULL
GROUP BY s9_.internal_order_id
HAVING minDue > NOW()
ORDER BY minDue ASC
AND s11_.deleted = 0
otherwise you might be excluding some revisions on the basis that there is a more recent, but deleted, revision.deleted = 0
filter is simply unnecessary fors11_
.deleted = 0
is unnecessary, but have a look at this example that I prepared to demonstrate: sqlfiddle.com/#!9/7e4b7e Of course trying to guess the business rules of someone else's database is ultimately futile... if they want it to behave this way then of course it is correct.due
andNOW()
. The first query will return any order which has adue
date after today, the second will return only orders where the firstdue
is after today.