WITH RECURSIVE input(sud) AS ( VALUES('53..7....6..195....98....6.8...6...34..8.3..17...2...6.6....28....419..5....8..79') ), digits(z, lp) AS ( VALUES('1', 1) UNION ALL SELECT CAST(lp+1 AS TEXT), lp+1 FROM digits WHERE lp<9 ), x(s, ind) AS ( SELECT sud, instr(sud, '.') FROM input UNION ALL SELECT substr(s, 1, ind-1) || z || substr(s, ind+1), instr(substr(s, 1, ind-1) || z || substr(s, ind+1), '.') FROM x, digits AS z WHERE ind>0 AND NOT EXISTS ( SELECT 1 FROM digits AS lp WHERE z.z = substr(s, ((ind-1)/9)*9 + lp, 1) OR z.z = substr(s, ((ind-1)%9) + (lp-1)*9 + 1, 1) OR z.z = substr(s, (((ind-1)/3) % 3)*3 + ((ind-1)/27)*27 + lp + ((lp-1)/3)*6, 1) ) ), solved(s) AS ( SELECT s FROM x WHERE ind=0 ), -- Build 9 pretty rows for both input and solved using digits.lp = 1..9 grid_rows(name, rn, line) AS ( SELECT 'input', d.lp, substr(sud, (d.lp-1)*9+1, 3) || ' | ' || substr(sud, (d.lp-1)*9+4, 3) || ' | ' || substr(sud, (d.lp-1)*9+7, 3) FROM input CROSS JOIN digits d UNION ALL SELECT 'solved', d.lp, substr(s, (d.lp-1)*9+1, 3) || ' | ' || substr(s, (d.lp-1)*9+4, 3) || ' | ' || substr(s, (d.lp-1)*9+7, 3) FROM solved CROSS JOIN digits d ), -- Insert horizontal separators after rows 3 and 6 by computing an ordering key grid_with_sep AS ( SELECT name, rn*2-1 AS ord, line FROM grid_rows UNION ALL SELECT name, rn*2 AS ord, '----+-----+----' FROM grid_rows WHERE rn IN (3,6) ) -- Single final UNIONed selection, ordered by group + position SELECT line FROM ( SELECT 1 AS grp, ord AS ord, line FROM grid_with_sep WHERE name='input' UNION ALL SELECT 2 AS grp, 0 AS ord, '' AS line UNION ALL SELECT 3 AS grp, ord AS ord, line FROM grid_with_sep WHERE name='solved' ) ORDER BY grp, ord;