Reputation: 571
How can i get rif of theses subqueries ?
(all tables have columns Created and LastEdited as timestamps)
table Process
- ID
- Title
table ProcessHistory
- ID
- ProcessID
- HistoryID
table History
- ID
- Title (new, open, closed etc.)
When i try to get a list of processes with cols of the last status title i do:
SELECT DISTINCT Process.*, History.Title AS HistoryTitle, History.ID AS HistoryID
FROM `Process`
LEFT JOIN ProcessHistory AS ProcessHistory ON Process.ID=ProcessHistory.ProcessID
LEFT JOIN History AS History ON HistoryID=ProcessHistory.HistoryID
WHERE History.ID = (
SELECT HistoryID FROM ProcessHistory
WHERE ProcessID=Process.ID
ORDER BY ProcessHistory.ID DESC LIMIT 1
)
GROUP BY Process.ID
ORDER BY Process.ID DESC LIMIT 0, 100
When i try to get a list filtered by a specific status (Where the latest HistoryID is 1 - "all open Processes")
SELECT DISTINCT Process.*, History.Title AS HistoryTitle, History.ID AS HistoryID
FROM `Process`
LEFT JOIN ProcessHistory AS ProcessHistory ON Process.ID=ProcessHistory.ProcessID
LEFT JOIN History AS History ON HistoryID=ProcessHistory.HistoryID
WHERE History.ID=(
SELECT HistoryID FROM ProcessHistory
WHERE HistoryID =1
AND ProcessID=Process.ID ORDER BY ProcessHistory.ID DESC LIMIT 1
)
GROUP BY Process.ID
ORDER BY Process.ID DESC LIMIT 0, 100
For performance reasons i want to get rid of theses subqueries? How can i replace the subquery?
Thanks in advance !
Upvotes: 0
Views: 211
Reputation: 2191
You'll still need to make another select to filter out the rest of the process history, but you should use a derived table instead of a subquery, like this sqlfiddle:
SELECT Process.*, History.Title AS HistoryTitle
FROM Process
JOIN (
SELECT ProcessID, max(HistoryID) as HistoryID
FROM ProcessHistory
GROUP BY ProcessID
) PH ON PH.ProcessID = Process.ID
JOIN History ON History.ID = PH.HistoryID
ORDER BY Process.ID DESC LIMIT 0, 100
As Himanshu Patel pointed out, your query to "get a list filtered by a specific status (Where the latest HistoryID is 1 - "all open Processes")" will not produce the desired effect. It will simply return all processes that have a HistoryID of 1. See this sqlfiddle.
Instead, you want to use a derived table to get those latest process history ids, join them with the processes, and filter on the history ids like this sqlfiddle:
SELECT DISTINCT Process.*, History.Title AS HistoryTitle
FROM Process
JOIN (
SELECT ProcessID, max(HistoryID) as HistoryID
FROM ProcessHistory
GROUP BY ProcessID
) PH ON PH.ProcessID = Process.ID
JOIN History ON History.ID = PH.HistoryID
WHERE PH.HistoryID = 1
ORDER BY Process.ID DESC LIMIT 0, 100
An alternative approach would be to create a view that filters the ProcessHistory table to the latest history per process and join on that. YMMV, but in some cases, performance can be improved that way.
Upvotes: 0
Reputation: 15941
Due to the actual subquery, used to get "last" row related to each "process", you can neither convert it to a JOIN nor can you use it as a separate query to set a session variable.
Upvotes: 0
Reputation: 2278
SELECT *
FROM Process AS p
LEFT JOIN (
SELECT ph.ProcessID, ph.HistoryID, h.Title AS HistoryTitle
FROM ProcessHistory AS ph
JOIN History AS h ON ph.HistoryID = h.ID
WHERE h.ID = 1
) AS phh ON p.ID = phh.ProcessID
ORDER BY p.ID DESC LIMIT 100
Upvotes: 0
Reputation: 243
Query you posted not give proper result as per ORDER BY ProcessHistory.ID DESC LIMIT 1
Try below query as per result of your query
SELECT DISTINCT p.*, h.Title AS HistoryTitle,h.ID AS HistoryID
FROM
Process p JOIN ProcessHistory ph ON p.ID=ph.ProcessID and ph.HistoryID=1
JOIN History h ON h.ID=ph.HistoryID
GROUP BY p.ID
ORDER BY p.ID DESC LIMIT 0, 100;
Here the sql fiddle:
sql fiddle link
If you want other result then comment.
Upvotes: 3