123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475 |
- # Copyright Materialize, Inc. and contributors. All rights reserved.
- #
- # Use of this software is governed by the Business Source License
- # included in the LICENSE file at the root of this repository.
- #
- # As of the Change Date specified in that file, in accordance with
- # the Business Source License, use of this software will be governed
- # by the Apache License, Version 2.0.
- # https://github.com/MaterializeInc/advent-of-code-2023/blob/main/week1/aoc_1203.md
- mode cockroach
- statement ok
- CREATE TABLE input (input TEXT);
- statement ok
- INSERT INTO input VALUES (
- '...14...954......104...98..........11...222.........38.104....708..........................217..................330.................19..
- .......@...................*...............................*.664........677................@....459.........187..........73.............
- ....41............178.....398....*...548..495..........983.........99.........282......409........*...........$.248...............165...
- ......261......300...............704.&.......*.......*........9.65..904.....6....*773....=.....680../511...2*.....=..99*....*..../......
- ..........200..............398.......22...100...........&...........10.......*.......73.....833...*...........*......300.............22.
- ..................@.100....*...........*...............*....19...300.....*.................@....954.......................200...........
- .....-....&..@............828...........@268..844....534...................563.........409........$..........244.........722.286........');
- query II
- WITH MUTUALLY RECURSIVE
- -- PART 0
- -- Parse the input as lines of text with line numbers.
- lines(line TEXT, row_idx INT) AS (
- SELECT
- regexp_split_to_array(input, '\n')[row_idx],
- row_idx
- FROM
- input,
- generate_series(1, (SELECT COUNT(*)::INT FROM (SELECT regexp_split_to_table(input, '\n') FROM input))) as row_idx
- ),
- chars(symbol TEXT, row_idx INT, col_idx INT) AS (
- SELECT
- substring(line, start, 1),
- row_idx,
- start
- FROM
- lines,
- generate_series(1, length(line)) as start
- WHERE
- substring(line, start, 1) != '.'
- ),
- numerals(number TEXT, row_idx INT, col_idx INT) AS (
- SELECT symbol, row_idx, col_idx
- FROM chars
- WHERE symbol IN ( VALUES ('0'), ('1'), ('2'), ('3'), ('4'), ('5'), ('6'), ('7'), ('8'), ('9') )
- ),
- symbols(symbol TEXT, row_idx INT, col_idx INT) AS (
- SELECT symbol, row_idx, col_idx
- FROM chars
- WHERE symbol NOT IN ( VALUES ('0'), ('1'), ('2'), ('3'), ('4'), ('5'), ('6'), ('7'), ('8'), ('9') )
- ),
- -- PART 1
- -- Recursively build up ranges of numerals that are "active", in the sense of being adjacent to a symbol.
- -- Each range has an accumulated number (as a string), a row index, a column index and length of the run.
- active(number TEXT, row_idx INT, col_idx INT, length INT) AS (
- -- Base case: numerals adjacent to a symbol
- SELECT numerals.*, 1
- FROM
- numerals,
- symbols,
- generate_series(-1, 1) row_off,
- generate_series(-1, 1) col_off
- WHERE numerals.row_idx = symbols.row_idx + row_off
- AND numerals.col_idx = symbols.col_idx + col_off
- UNION
- -- Inductive case 1: Join to the left
- SELECT numerals.number || active.number, numerals.row_idx, numerals.col_idx, active.length + 1
- FROM numerals, active
- WHERE numerals.row_idx = active.row_idx
- AND numerals.col_idx = active.col_idx - 1
- UNION
- -- Inductive case 2: Join to the right
- SELECT active.number || numerals.number, numerals.row_idx, active.col_idx, active.length + 1
- FROM numerals, active
- WHERE numerals.row_idx = active.row_idx
- AND numerals.col_idx = active.col_idx + active.length
- ),
- parts(number INT, row_idx INT, col_idx INT, length INT) AS (
- SELECT active.number::INT, row_idx, col_idx, length
- FROM active
- WHERE (active.row_idx, active.col_idx-1) NOT IN (SELECT row_idx, col_idx FROM numerals)
- AND (active.row_idx, active.col_idx+length) NOT IN (SELECT row_idx, col_idx FROM numerals)
- ),
- part1(part1 BIGINT) AS ( SELECT SUM(parts.number::INT) FROM parts ),
- -- PART 2
- -- A "gear" is a `*` adjacent to exactly two part numbers. We want the sum over gears of their product.
- -- A gear is identified by a location, which we will want to attempt to join with part numbers.
- gear_adjacent(row_idx INT, col_idx INT, number INT, part_row INT, part_col INT) AS (
- SELECT DISTINCT symbols.row_idx, symbols.col_idx, parts.number, parts.row_idx, parts.col_idx
- FROM
- symbols,
- generate_series(-1, 1) gear_r_off,
- generate_series(-1, 1) gear_c_off,
- parts,
- generate_series(parts.col_idx, parts.col_idx + parts.length - 1) part_col
- WHERE symbols.symbol = '*'
- AND symbols.row_idx + gear_r_off = parts.row_idx
- AND symbols.col_idx + gear_c_off = part_col
- ),
- gears(row_idx INT, col_idx INT) AS (
- SELECT row_idx, col_idx
- FROM gear_adjacent
- GROUP BY row_idx, col_idx
- HAVING COUNT(*) = 2
- ),
- gear_products(row_idx INT, col_idx INT, product INT) AS (
- SELECT DISTINCT gears.row_idx, gears.col_idx, p1.number * p2.number
- FROM gears, gear_adjacent p1, gear_adjacent p2
- WHERE gears.row_idx = p1.row_idx
- AND gears.col_idx = p1.col_idx
- AND gears.row_idx = p2.row_idx
- AND gears.col_idx = p2.col_idx
- AND (p1.part_row != p2.part_row OR p1.part_col != p2.part_col)
- ),
- part2(part2 BIGINT) AS ( SELECT SUM(product) FROM gear_products)
- SELECT * FROM part1, part2;
- ----
- 11374 1587570
- query T multiline
- EXPLAIN OPTIMIZED PLAN WITH(humanized expressions, arity, join implementations) AS VERBOSE TEXT FOR
- WITH MUTUALLY RECURSIVE
- -- PART 0
- -- Parse the input as lines of text with line numbers.
- lines(line TEXT, row_idx INT) AS (
- SELECT
- regexp_split_to_array(input, '\n')[row_idx],
- row_idx
- FROM
- input,
- generate_series(1, (SELECT COUNT(*)::INT FROM (SELECT regexp_split_to_table(input, '\n') FROM input))) as row_idx
- ),
- chars(symbol TEXT, row_idx INT, col_idx INT) AS (
- SELECT
- substring(line, start, 1),
- row_idx,
- start
- FROM
- lines,
- generate_series(1, length(line)) as start
- WHERE
- substring(line, start, 1) != '.'
- ),
- numerals(number TEXT, row_idx INT, col_idx INT) AS (
- SELECT symbol, row_idx, col_idx
- FROM chars
- WHERE symbol IN ( VALUES ('0'), ('1'), ('2'), ('3'), ('4'), ('5'), ('6'), ('7'), ('8'), ('9') )
- ),
- symbols(symbol TEXT, row_idx INT, col_idx INT) AS (
- SELECT symbol, row_idx, col_idx
- FROM chars
- WHERE symbol NOT IN ( VALUES ('0'), ('1'), ('2'), ('3'), ('4'), ('5'), ('6'), ('7'), ('8'), ('9') )
- ),
- -- PART 1
- -- Recursively build up ranges of numerals that are "active", in the sense of being adjacent to a symbol.
- -- Each range has an accumulated number (as a string), a row index, a column index and length of the run.
- active(number TEXT, row_idx INT, col_idx INT, length INT) AS (
- -- Base case: numerals adjacent to a symbol
- SELECT numerals.*, 1
- FROM
- numerals,
- symbols,
- generate_series(-1, 1) row_off,
- generate_series(-1, 1) col_off
- WHERE numerals.row_idx = symbols.row_idx + row_off
- AND numerals.col_idx = symbols.col_idx + col_off
- UNION
- -- Inductive case 1: Join to the left
- SELECT numerals.number || active.number, numerals.row_idx, numerals.col_idx, active.length + 1
- FROM numerals, active
- WHERE numerals.row_idx = active.row_idx
- AND numerals.col_idx = active.col_idx - 1
- UNION
- -- Inductive case 2: Join to the right
- SELECT active.number || numerals.number, numerals.row_idx, active.col_idx, active.length + 1
- FROM numerals, active
- WHERE numerals.row_idx = active.row_idx
- AND numerals.col_idx = active.col_idx + active.length
- ),
- parts(number INT, row_idx INT, col_idx INT, length INT) AS (
- SELECT active.number::INT, row_idx, col_idx, length
- FROM active
- WHERE (active.row_idx, active.col_idx-1) NOT IN (SELECT row_idx, col_idx FROM numerals)
- AND (active.row_idx, active.col_idx+length) NOT IN (SELECT row_idx, col_idx FROM numerals)
- ),
- part1(part1 BIGINT) AS ( SELECT SUM(parts.number::INT) FROM parts ),
- -- PART 2
- -- A "gear" is a `*` adjacent to exactly two part numbers. We want the sum over gears of their product.
- -- A gear is identified by a location, which we will want to attempt to join with part numbers.
- gear_adjacent(row_idx INT, col_idx INT, number INT, part_row INT, part_col INT) AS (
- SELECT DISTINCT symbols.row_idx, symbols.col_idx, parts.number, parts.row_idx, parts.col_idx
- FROM
- symbols,
- generate_series(-1, 1) gear_r_off,
- generate_series(-1, 1) gear_c_off,
- parts,
- generate_series(parts.col_idx, parts.col_idx + parts.length - 1) part_col
- WHERE symbols.symbol = '*'
- AND symbols.row_idx + gear_r_off = parts.row_idx
- AND symbols.col_idx + gear_c_off = part_col
- ),
- gears(row_idx INT, col_idx INT) AS (
- SELECT row_idx, col_idx
- FROM gear_adjacent
- GROUP BY row_idx, col_idx
- HAVING COUNT(*) = 2
- ),
- gear_products(row_idx INT, col_idx INT, product INT) AS (
- SELECT DISTINCT gears.row_idx, gears.col_idx, p1.number * p2.number
- FROM gears, gear_adjacent p1, gear_adjacent p2
- WHERE gears.row_idx = p1.row_idx
- AND gears.col_idx = p1.col_idx
- AND gears.row_idx = p2.row_idx
- AND gears.col_idx = p2.col_idx
- AND (p1.part_row != p2.part_row OR p1.part_col != p2.part_col)
- ),
- part2(part2 BIGINT) AS ( SELECT SUM(product) FROM gear_products)
- SELECT * FROM part1, part2;
- ----
- Explained Query:
- With
- cte l0 =
- Reduce aggregates=[count(*)] // { arity: 1 }
- Project () // { arity: 0 }
- FlatMap unnest_array(regexp_split_to_array["\n", case_insensitive=false](#0{input})) // { arity: 2 }
- ReadStorage materialize.public.input // { arity: 1 }
- cte l1 =
- Project (#0, #2, #3) // { arity: 3 }
- Filter (#3 != ".") // { arity: 4 }
- Map (substr(#1{line}, #2{start}, 1)) // { arity: 4 }
- FlatMap generate_series(1, char_length(#1{line}), 1) // { arity: 3 }
- Project (#1, #2) // { arity: 2 }
- Map (array_index(regexp_split_to_array["\n", case_insensitive=false](#0{input}), integer_to_bigint(#1{row_idx}))) // { arity: 3 }
- CrossJoin type=differential // { arity: 2 }
- implementation
- %0:input[×] » %1[×]
- ArrangeBy keys=[[]] // { arity: 1 }
- ReadStorage materialize.public.input // { arity: 1 }
- ArrangeBy keys=[[]] // { arity: 1 }
- Project (#1) // { arity: 1 }
- FlatMap generate_series(1, #0, 1) // { arity: 2 }
- Project (#1) // { arity: 1 }
- Map (bigint_to_integer(#0{count})) // { arity: 2 }
- Union // { arity: 1 }
- Get l0 // { arity: 1 }
- Map (0) // { arity: 1 }
- Union // { arity: 0 }
- Negate // { arity: 0 }
- Project () // { arity: 0 }
- Get l0 // { arity: 1 }
- Constant // { arity: 0 }
- - ()
- cte l2 =
- Distinct project=[#0] // { arity: 1 }
- Project (#2) // { arity: 1 }
- Get l1 // { arity: 3 }
- cte l3 =
- Distinct project=[#0] // { arity: 1 }
- Project (#0) // { arity: 1 }
- Filter (#0{symbol} = #1{right_col0_0}) // { arity: 2 }
- FlatMap wrap1("0", "1", "2", "3", "4", "5", "6", "7", "8", "9") // { arity: 2 }
- Get l2 // { arity: 1 }
- cte l4 =
- ArrangeBy keys=[[#2]] // { arity: 3 }
- Get l1 // { arity: 3 }
- cte l5 =
- Project (#0..=#2) // { arity: 3 }
- Join on=(#2 = #3) type=differential // { arity: 4 }
- implementation
- %1:l3[#0]UKA » %0:l4[#2]K
- Get l4 // { arity: 3 }
- ArrangeBy keys=[[#0]] // { arity: 1 }
- Get l3 // { arity: 1 }
- cte l6 =
- Project (#0..=#2) // { arity: 3 }
- Join on=(#2 = #3) type=differential // { arity: 4 }
- implementation
- %0:l4[#2]K » %1[#0]K
- Get l4 // { arity: 3 }
- ArrangeBy keys=[[#0]] // { arity: 1 }
- Union // { arity: 1 }
- Negate // { arity: 1 }
- Get l3 // { arity: 1 }
- Get l2 // { arity: 1 }
- cte l7 =
- ArrangeBy keys=[[]] // { arity: 1 }
- Constant // { arity: 1 }
- - (0)
- - (-1)
- - (1)
- cte l8 =
- ArrangeBy keys=[[#0{row_idx}, #1{col_idx}]] // { arity: 3 }
- Get l5 // { arity: 3 }
- Return // { arity: 2 }
- With Mutually Recursive
- cte l9 =
- Distinct project=[#0..=#3] // { arity: 4 }
- Union // { arity: 4 }
- Distinct project=[#0..=#3] // { arity: 4 }
- Union // { arity: 4 }
- Project (#2, #0, #1, #7) // { arity: 4 }
- Map (1) // { arity: 8 }
- Join on=(#0{row_idx} = (#3{row_idx} + #5{row_off}) AND #1{col_idx} = (#4{col_idx} + #6{col_off})) type=delta // { arity: 7 }
- implementation
- %0:l5 » %1:l6[×] » %2:l7[×] » %3:l7[×]
- %1:l6 » %0:l5[×] » %2:l7[×] » %3:l7[×]
- %2:l7 » %0:l5[×] » %1:l6[×] » %3:l7[×]
- %3:l7 » %0:l5[×] » %1:l6[×] » %2:l7[×]
- ArrangeBy keys=[[]] // { arity: 3 }
- Get l5 // { arity: 3 }
- ArrangeBy keys=[[]] // { arity: 2 }
- Project (#0, #1) // { arity: 2 }
- Get l6 // { arity: 3 }
- Get l7 // { arity: 1 }
- Get l7 // { arity: 1 }
- Project (#7, #0, #1, #8) // { arity: 4 }
- Map ((#2{number} || #3{number}), (#6{length} + 1)) // { arity: 9 }
- Join on=(#0{row_idx} = #4{row_idx} AND #1{col_idx} = (#5{col_idx} - 1)) type=differential // { arity: 7 }
- implementation
- %0:l8[#0{row_idx}, #1{col_idx}]KK » %1:l9[#1{row_idx}, (#2{col_idx} - 1)]KK
- Get l8 // { arity: 3 }
- ArrangeBy keys=[[#1{row_idx}, (#2{col_idx} - 1)]] // { arity: 4 }
- Get l9 // { arity: 4 }
- Project (#7, #0, #5, #8) // { arity: 4 }
- Map ((#3{number} || #2{number}), (#6{length} + 1)) // { arity: 9 }
- Join on=(#0{row_idx} = #4{row_idx} AND #1{col_idx} = (#5{col_idx} + #6{length})) type=differential // { arity: 7 }
- implementation
- %0:l8[#0{row_idx}, #1{col_idx}]KK » %1:l9[#1{row_idx}, (#2{col_idx} + #3{length})]KK
- Get l8 // { arity: 3 }
- ArrangeBy keys=[[#1{row_idx}, (#2{col_idx} + #3{length})]] // { arity: 4 }
- Get l9 // { arity: 4 }
- Return // { arity: 2 }
- With
- cte l10 =
- Distinct project=[#0, #1] // { arity: 2 }
- Project (#1, #2) // { arity: 2 }
- Get l9 // { arity: 4 }
- cte l11 =
- ArrangeBy keys=[[#0{right_col0_4}, #1{right_col1_5}]] // { arity: 2 }
- Project (#0, #1) // { arity: 2 }
- Get l5 // { arity: 3 }
- cte l12 =
- Project (#0..=#3) // { arity: 4 }
- Join on=(#1 = #4 AND #2 = #5) type=differential // { arity: 6 }
- implementation
- %0:l9[#1, #2]KK » %1[#0, #1]KK
- ArrangeBy keys=[[#1, #2]] // { arity: 4 }
- Get l9 // { arity: 4 }
- ArrangeBy keys=[[#0, #1]] // { arity: 2 }
- Union // { arity: 2 }
- Negate // { arity: 2 }
- Distinct project=[#0, #1] // { arity: 2 }
- Project (#0, #1) // { arity: 2 }
- Join on=(#0{row_idx} = #2{right_col0_4} AND #3{right_col1_5} = (#1{col_idx} - 1)) type=differential // { arity: 4 }
- implementation
- %0:l10[#0{row_idx}, (#1{col_idx} - 1)]KK » %1:l11[#0{right_col0_4}, #1{right_col1_5}]KK
- ArrangeBy keys=[[#0{row_idx}, (#1{col_idx} - 1)]] // { arity: 2 }
- Get l10 // { arity: 2 }
- Get l11 // { arity: 2 }
- Get l10 // { arity: 2 }
- cte l13 =
- Distinct project=[#0..=#2] // { arity: 3 }
- Project (#1..=#3) // { arity: 3 }
- Get l12 // { arity: 4 }
- cte l14 =
- Project (#1..=#3, #7) // { arity: 4 }
- Map (text_to_integer(#0{number})) // { arity: 8 }
- Join on=(#1 = #4 AND #2 = #5 AND #3 = #6) type=differential // { arity: 7 }
- implementation
- %0:l12[#1..=#3]KKK » %1[#0..=#2]KKK
- ArrangeBy keys=[[#1..=#3]] // { arity: 4 }
- Get l12 // { arity: 4 }
- ArrangeBy keys=[[#0..=#2]] // { arity: 3 }
- Union // { arity: 3 }
- Negate // { arity: 3 }
- Distinct project=[#0..=#2] // { arity: 3 }
- Project (#0..=#2) // { arity: 3 }
- Join on=(#0{row_idx} = #3{right_col0_7} AND #4{right_col1_8} = (#1{col_idx} + #2{length})) type=differential // { arity: 5 }
- implementation
- %0:l13[#0{row_idx}, (#1{col_idx} + #2{length})]KK » %1:l11[#0{right_col0_7}, #1{right_col1_8}]KK
- ArrangeBy keys=[[#0{row_idx}, (#1{col_idx} + #2{length})]] // { arity: 3 }
- Get l13 // { arity: 3 }
- Get l11 // { arity: 2 }
- Get l13 // { arity: 3 }
- cte l15 =
- Reduce aggregates=[sum(#0{number})] // { arity: 1 }
- Project (#3) // { arity: 1 }
- Get l14 // { arity: 4 }
- cte l16 =
- ArrangeBy keys=[[]] // { arity: 1 }
- Constant // { arity: 1 }
- - (0)
- - (-1)
- - (1)
- cte l17 =
- Distinct project=[#0, #1, #4, #2, #3] // { arity: 5 }
- Project (#0, #1, #3, #4, #6) // { arity: 5 }
- Filter (#7{part_col} = (#1{col_idx} + #2{gear_c_off})) // { arity: 8 }
- FlatMap generate_series(#4{col_idx}, ((#4{col_idx} + #5{length}) - 1), 1) // { arity: 8 }
- Project (#0, #1, #3..=#7) // { arity: 7 }
- Join on=(#4{row_idx} = (#0{row_idx} + #2{gear_r_off})) type=delta // { arity: 8 }
- implementation
- %0:l6 » %1:l16[×] » %3:l14[#0{row_idx}]K » %2:l16[×]
- %1:l16 » %0:l6[×]ef » %3:l14[#0{row_idx}]K » %2:l16[×]
- %2:l16 » %0:l6[×]ef » %1:l16[×] » %3:l14[#0{row_idx}]K
- %3:l14 » %0:l6[×]ef » %1:l16[×] » %2:l16[×]
- ArrangeBy keys=[[]] // { arity: 2 }
- Project (#0, #1) // { arity: 2 }
- Filter (#2{symbol} = "*") // { arity: 3 }
- Get l6 // { arity: 3 }
- Get l16 // { arity: 1 }
- Get l16 // { arity: 1 }
- ArrangeBy keys=[[#0{row_idx}]] // { arity: 4 }
- Get l14 // { arity: 4 }
- cte l18 =
- ArrangeBy keys=[[#0{row_idx}, #1{col_idx}]] // { arity: 5 }
- Get l17 // { arity: 5 }
- cte l19 =
- Reduce aggregates=[sum(#0{product})] // { arity: 1 }
- Project (#2) // { arity: 1 }
- Distinct project=[#0, #1, (#2{number} * #3{number})] // { arity: 3 }
- Project (#0, #1, #5, #10) // { arity: 4 }
- Filter (#2{count} = 2) AND ((#6{part_row} != #11{part_row}) OR (#7{part_col} != #12{part_col})) // { arity: 13 }
- Join on=(#0{row_idx} = #3{row_idx} = #8{row_idx} AND #1{col_idx} = #4{col_idx} = #9{col_idx}) type=delta // { arity: 13 }
- implementation
- %0 » %1:l18[#0{row_idx}, #1{col_idx}]KK » %2:l18[#0{row_idx}, #1{col_idx}]KK
- %1:l18 » %0[#0, #1]UKKAef » %2:l18[#0{row_idx}, #1{col_idx}]KK
- %2:l18 » %0[#0, #1]UKKAef » %1:l18[#0{row_idx}, #1{col_idx}]KK
- ArrangeBy keys=[[#0, #1]] // { arity: 3 }
- Reduce group_by=[#0, #1] aggregates=[count(*)] // { arity: 3 }
- Project (#0, #1) // { arity: 2 }
- Get l17 // { arity: 5 }
- Get l18 // { arity: 5 }
- Get l18 // { arity: 5 }
- Return // { arity: 2 }
- CrossJoin type=differential // { arity: 2 }
- implementation
- %0[×]U » %1[×]U
- ArrangeBy keys=[[]] // { arity: 1 }
- Union // { arity: 1 }
- Get l15 // { arity: 1 }
- Map (null) // { arity: 1 }
- Union // { arity: 0 }
- Negate // { arity: 0 }
- Project () // { arity: 0 }
- Get l15 // { arity: 1 }
- Constant // { arity: 0 }
- - ()
- ArrangeBy keys=[[]] // { arity: 1 }
- Union // { arity: 1 }
- Get l19 // { arity: 1 }
- Map (null) // { arity: 1 }
- Union // { arity: 0 }
- Negate // { arity: 0 }
- Project () // { arity: 0 }
- Get l19 // { arity: 1 }
- Constant // { arity: 0 }
- - ()
- Source materialize.public.input
- Target cluster: quickstart
- EOF
|