I don't think there's a way without nested OLAP, e.g.
QUALIFY -- start with the latest row and go on as long as the TYPE_CD doesn't change
MIN(type_cd) OVER (PARTITION BY D ORDER BY per_dt DESC ROWS UNBOUNDED PRECEDING) =
MAX(type_cd) OVER (PARTITION BY D ORDER BY per_dt DESC ROWS UNBOUNDED PRECEDING)
) AS dt
QUALIFY -- find the oldest row
ROW_NUMBER() OVER (PARTITION BY D ORDER BY per_dt ASC) = 1
On (only) 30 million rows this should be resonable fast...
Thank you, it helped me a lot. I didnt know about "unbounded" syntax.