














with recursive coordinates as materialized (selectrow * 9 + col + 1 as id,row,col,row / 3 * 3 + col / 3 as boxfromgenerate_series(0, 8) as rs(row),generate_series(0, 8) as cs(col)), propagations as materialized (selectsources.id as coordinate_id,bit_or(bitshiftright(set_bit(0::bit(729), 0, 1), (targets.id - 1) * 9)) as targetsfromcoordinates as sourcesinner joincoordinates as targetsonsources.row = targets.rowor sources.col = targets.color sources.box = targets.boxgroup bysources.id), cells as materialized (selectid,coordinate_id::int as coordinate_id,digitfromsudoku9_9 as sudoku,unnest(string_to_array(replace(replace(puzzle, E'\n', ''), '?', '0'), null)::int[]) with ordinality as _(digit, coordinate_id)), almosts as materialized (selectcells.id,bitnot(bit_or(bitshiftright(propagations.targets, cells.digit - 1))) as candidatesfromcellsinner joinpropagationsoncells.coordinate_id = propagations.coordinate_idand cells.digit != 0group bycells.id), constraints as materialized (selectcells.id,cells.coordinate_id,set_bit(set_bit(set_bit(overlay(b'000000000000000000000000000000000000' placing substring(almosts.candidates from (cells.coordinate_id - 1) * 9 + 1 for 9) from 1 for 9), coordinates.row + 9, 1), coordinates.col + 18, 1), coordinates.box + 27, 1) as candidatesfromcellsinner joinalmostsoncells.id = almosts.idand cells.digit = 0inner joincoordinatesoncells.coordinate_id = coordinates.id), puzzles as (selectconstraints.id,count(distinct constraints.coordinate_id) as size,'{}'::int[] as solution,array_agg(set_bit(set_bit(set_bit(constraints.candidates, coordinates.row + 9, 1), coordinates.col + 18, 1), coordinates.box + 27, 1) order by bit_count(constraints.candidates)) as candidatesfromconstraintsinner joincoordinatesonconstraints.coordinate_id = coordinates.idgroup byconstraints.idunion allselectid,size,array_append(solution,casewhen get_bit(candidates[1], 9) = 1 then 100when get_bit(candidates[1], 10) = 1 then 200when get_bit(candidates[1], 11) = 1 then 300when get_bit(candidates[1], 12) = 1 then 400when get_bit(candidates[1], 13) = 1 then 500when get_bit(candidates[1], 14) = 1 then 600when get_bit(candidates[1], 15) = 1 then 700when get_bit(candidates[1], 16) = 1 then 800else 900end+ casewhen get_bit(candidates[1], 18) = 1 then 10when get_bit(candidates[1], 19) = 1 then 20when get_bit(candidates[1], 20) = 1 then 30when get_bit(candidates[1], 21) = 1 then 40when get_bit(candidates[1], 22) = 1 then 50when get_bit(candidates[1], 23) = 1 then 60when get_bit(candidates[1], 24) = 1 then 70when get_bit(candidates[1], 25) = 1 then 80else 90end+ digit + 1) as solution,array(selectcasewhenget_bit(candidate, digit) = 1and bit_count(candidates[1] & candidate & b'000000000111111111111111111111111111') > 0thenset_bit(candidate, digit, 0)elsecandidateend as candidatefromunnest(candidates[2:]) as _(candidate)order bybit_count(candidate)) as candidatesfrompuzzles,(values (0), (1), (2), (3), (4), (5), (6), (7), (8)) as _(digit)wherecardinality(candidates) > 0and bit_count(candidates[1]) > 3and get_bit(candidates[1], digit) = 1), solutions as (selectdistinct on (id)id,array(selectcandidate % 10fromunnest(solution) as _(candidate)order bycandidate) as solutionfrompuzzleswherecardinality(solution) = size)selectsudoku.id,sudoku.puzzle,format(replace(sudoku.puzzle, '?', '%s'), variadic solutions.solution) as resultfromsudoku9_9 as sudokuinner joinsolutionsonsudoku.id = solutions.id
感谢大家对本次《数据库编程大赛》的关注和支持,欢迎加入技术交流群,更多精彩活动不断,欢迎各路数据库爱好者来挑战!
