-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy patha8.sql
161 lines (151 loc) · 3.83 KB
/
a8.sql
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
create or replace database a8;
use a8;
create or replace table nums (
pos int not null,
val int not null
);
create sequence s;
load data local infile '/home/setorgan/aoc2018/a8test.txt'
into table nums
lines terminated by ' '
(@i)
set pos = nextval(s),
val = @i
;
create or replace table seed_table (
str varchar(5000)
);
insert into seed_table (str) values ('');
alter sequence s restart 1;
create or replace table nodes (
id int not null,
parent int not null,
metadata varchar(2000) not null
);
insert into nodes
with recursive parser as (
select
1 next,
'c' mode,
0 id,
0 parent,
str metadata,
0 cc,
0 cm,
concat(',0,0', str) qey,
concat(',0,0', str) ccs,
concat(',0,0', str) cms
from seed_table
union
select
case when mode = 'e' or (mode = 'v' and cm = 0) -- >end element
then next
else next + 1
end,
case when mode = 'c'
then 'm'
when (mode = 'm' or mode = 'e') and cc > 0 -- >next child
then 'c'
when (mode = 'm' or mode = 'e') and cc = 0 -- >read values
then 'v'
when mode = 'v' and cm = 0 -- >end element
then 'e'
when mode = 'e' and cc < 0 -- edge case no children no metadata
then 'c'
else mode
end,
case when (mode = 'm' or mode = 'e')
then cast(regexp_substr(qey, ',\\K\\d+\\z') as integer)
when mode = 'v' and cm = 0 -- >end element
then cast(regexp_substr(regexp_replace(qey, ',\\d+\\z', ''), ',\\K\\d+\\z') as integer)
else id
end,
case when mode = 'c'
then regexp_substr(qey, ',\\K\\d+\\z')
when mode = 'e'
then regexp_substr(regexp_replace(qey, ',\\d+\\z', ''), ',\\K\\d+\\z')
else parent
end,
case when (mode = 'm' or mode = 'e') and cc = 0
then ''
when mode = 'v' and cm > 0
then concat(metadata,',',val)
else metadata
end,
case when mode = 'v' and cm = 0 -- > end element
then regexp_substr(regexp_replace(ccs, ',\\d+\\z', ''), ',\\K-?\\d+\\z') - 1
when mode = 'c'
then val
else cc
end,
case when mode = 'v' and cm > 0
then cm - 1
when mode = 'v' and cm = 0 -- >end element
then regexp_substr(regexp_replace(cms, ',\\d+\\z', ''), ',-?\\K\\d+\\z')
when mode = 'm'
then val
else cm
end,
case when mode = 'c'
then concat(qey, ',', nextval(s))
when mode = 'v' and cm = 0 -- >end element
then regexp_replace(qey, ',\\d+\\z', '')
else qey
end,
case when mode ='c'
then concat(ccs,',',val)
when mode = 'v' and cm = 0 -- >end element
then regexp_replace(ccs, ',-?\\d+\\z', '')
when mode = 'e'
then regexp_replace(ccs, ',-?\\d+\\z', concat(',',cc))
else ccs
end,
case when mode = 'm'
then concat(cms,',',val)
when mode = 'v' and cm = 0 -- >end element
then regexp_replace(cms, ',-?\\d+\\z', '')
else cms
end
from parser join nums on pos = next
) select distinct
last_value(id) over w id,
last_value(parent) over w parent,
last_value(
case when length(metadata) > 0 then substr(metadata,2)
else metadata end
) over w metadata
from parser
where id > 0
window w as (partition by id order by next rows between unbounded preceding and unbounded following)
;
-- part 1
with recursive mv as (
select
1 n,
cast(regexp_substr(metadata, '\\d+') as unsigned integer) val,
regexp_replace(metadata, '\\A\\d+,?', '') mm
from nodes
where length(metadata) > 0
union all
select
n + 1,
cast(regexp_substr(mm, '\\d+') as unsigned integer) val,
regexp_replace(mm, '\\A\\d+,?', '') mm
from mv where length(mm) > 0
) select sum(val) from mv;
-- part 2
with recursive mv as (
select
id,
parent,
cast(regexp_substr(metadata, '\\d+') as unsigned integer) val,
regexp_replace(metadata, '\\A\\d+,?', '') mm
from nodes
where length(metadata) > 0
union all
select
n + 1,
cast(regexp_substr(mm, '\\d+') as unsigned integer) val,
regexp_replace(mm, '\\A\\d+,?', '') mm
from mv where length(mm) > 0
) select sum(val) from mv;