I’m trying to write a query that follows this logic:
Find the first following status code of an account that had a previous status code of X.
So if I have a table of:
id account_num status_code
64 1 X
82 1 Y
72 2 Y
87 1 Z
91 2 X
103 2 Z
The results would be:
id account_num status_code
82 1 Y
103 2 Z
I’ve come up with a couple of solutions but I’m not all that great with SQL and so they’ve been pretty inelegeant thus far. I was hoping that someone here might be able to point me in the right direction.
View:
SELECT account_number, id
FROM table
WHERE status_code = 'X'
Query:
SELECT account_number, min(id)
FROM table
INNER JOIN view
ON table.account_number = view.account_number
WHERE table.id > view.id
At this point I have the id that I need but I’d have to write ANOTHER query that uses the id tolook up the status_code.
Edit: To add some context, I’m trying to find calls that have a status_code of X. If a call has a status_code of X we want to dial it a different way the next time we make an attempt. The aim of this query is to provide a report that will show the results of the second dial if the first dial resulted an X status code.
Here’s a SQL Server solution.
UPDATE
The idea is to avoid a number of NESTED LOOP joins as proposed by Olaf because they roughly have O(N * M) complexity and thus extremely bad for your performance. MERGED JOINS complexity is O(NLog(N) + MLog(M)) which is much better for real world scenarios.
The query below works as follows:
RankedCTEis a subquery that assigns a row number to each id partioned by account and sorted by id which represents the time. So for the data below the output of thiswould be:
Once we have them numbered we join the result on itself like this:
which will give us an event and a preceding event in the same table
Finally, we just have to take the preceding event with code “X” and the event with code not “X”:
Query plans for this query and @Olaf Dietsche solution (one of the versions) are below.
Data setup script