Jeg tror, at dette kan løses ved hjælp af en rekursiv CTE:
with change_tree as
(
SELECT order_id,
previous_status_id,
next_status_id,
cast(next_status_id as varchar(max)) as status_path
FROM status_change
WHERE previous_status_id = 1
AND order_id = 2
UNION ALL
SELECT sc.order_id,
sc.previous_status_id,
sc.next_status_id,
ct.status_path + ',' + cast(sc.next_status_id as varchar(max))
FROM status_change sc
JOIN change_tree ct ON ct.next_status_id = sc.previous_status_id AND ct.order_id = sc.order_id
)
SELECT *
FROM change_tree
WHERE status_path = '2,3,5';
Hvad dette i bund og grund gør er at (rekursivt) sammenkæde alle værdier af next_status_id til en enkelt streng, som du kan sammenligne med.
Ud fra dine eksempeldata er det ikke klart for mig, hvilken række der markerer "begyndelsen" af en ordrestatusændringshistorik. Du bliver nødt til at justere hvor i den første del af foreningen for at vælge den korrekte "startende" række.