有没有办法将嵌套值列表从 json 列展平为不同值列表:
即:
from: {"unique_values":[["105125"],["105125"],["105125","0]]}
to: {"unique_values": ["105125","0"]
初步尝试使用:
json_transform()
将 json 转换为 repr 到实际列表flatten()
list_distinct()
删除重复项json_merge_patch()
将结果添加回 JSONtbl = duckdb.sql("""
from (values
('{"id":1,"values":[["1"],["1"],["1","0"]]}'),
('{"id":2,"values":[["2"],["3"],["1","3"]]}')
)
select col0::json as j
""")
duckdb.sql("""
from tbl
select json_merge_patch(j,
{
"values":
json_transform(j.values, '"VARCHAR[][]"')
.flatten()
.list_distinct()
}::json
) as j
"""
)
┌─────────────────────────────────┐
│ j │
│ json │
├─────────────────────────────────┤
│ {"values":["0","1"],"id":1} │
│ {"values":["1","3","2"],"id":2} │
└─────────────────────────────────┘
但是,一些潜在的问题:
list_distinct()
无法保留原来的值顺序。json_merge_patch()
失去原来的按键顺序。如果处理其他键和顺序很重要,似乎需要取消嵌套完整的 json 对象。
我在这里使用 json_group_struct() 来“动态”提取“模式”。
schema = duckdb.sql("""
from tbl select json_group_structure(j)
""").fetchone()[0]
'{"id":"UBIGINT","values":[["VARCHAR"]]}'
这有点啰嗦,因为我们手动取消嵌套、展平、区分,并使用 2 个单独的
row_number()
表达式来表示行和值顺序。
duckdb.sql(f"""
with
data as (
from tbl
select
row_number() over () row_number,
unnest(json_transform(j, '{schema}'))
),
distinct_data as (
from (
from data
select * replace unnest(values.flatten()) as values
)
select distinct on (row_number, values)
*,
row_number() over () as list_idx
),
distinct_lists as (
from distinct_data
select
first(columns(* exclude (values, list_idx))),
list(values order by list_idx) as values
group by id
order by row_number
),
result as (
from distinct_lists select * exclude row_number
)
from result
select result::json as j
""")
┌─────────────────────────────────┐
│ j │
│ json │
├─────────────────────────────────┤
│ {"id":1,"values":["1","0"]} │
│ {"id":2,"values":["2","3","1"]} │
└─────────────────────────────────┘
我希望有一种方法可以简化这个过程。