将单个 postgres jsonb 数组元素转换为行元素
Convert individual postgres jsonb array elements to row elements
我必须查询一个包含 2 列的 table,id 和 content。 Id 只是一个 uuid,内容栏看起来像
{
"fields": [
{
"001": "mig00004139229"
},
{
"856": {
"ind1": " ",
"ind2": " ",
"subfields": [
{
"u": "https://some.domain.com"
},
{
"z": "some text"
}
]
}
},
{
"999": {
"subfields": [
{
"i": "81be1acf-11df-4d13-a5c6-4838e3a808ee"
},
{
"s": "3a6aa357-8fd6-4451-aedc-13453c1f2296"
}
]
}
}
]
}
我需要 select 子字段“u”域与字符串“domain.com”匹配的 id、001 和 856 元素,因此输出将是
id
001
856
81be1acf-11df-4d13-a5c6-4838e3a808ee
mig00004139229
https://some.domain.com
如果这是一个平面 table,查询将对应于“select id, 001, 856 from table where 856 like '%domain.com%' “
我可以根据我需要的条件 select 单独的列,但它们出现在单独的行中,除了在常规 select 语句中与任何其他单独字段一起出现的 id。我怎样才能让其他字段出现在同一行中,因为它是同一记录的一部分?
不幸的是,我的 postgres 版本不支持 jsonb_path_query,所以我一直在尝试以下方法:
SELECT id, jsonb_array_elements(content -> 'fields') -> '001',
jsonb_array_elements(content -> 'fields') -> '856' -> 'subfields'
FROM
mytable
WHERE....
此方法 returns 我需要的数据,但各个元素到达单独的行,第一列中带有 id,每个元素都为 null,既不是 001 也不是 856,例如
id
001
856
id_for_first_record
001_first_record
null
id_for_first_record
null
null
id_for_first_record
null
null
id_for_first_record
null
856_first_record
id_for_second_record
001_second_record
null
id_for_second_record
null
null
id_for_second_record
null
null
id_for_second_record
null
856_second_record
可用,但笨重,所以我正在寻找更好的东西
我想我的查询可以帮到你。有多种方法可以解决这个问题,我不确定这是否是最好的方法。
我将 jsonb_path_query()
函数与指定 JSON
值的路径一起使用。
SELECT
id,
jsonb_path_query(content, '$.fields[*]."001"') AS "001",
jsonb_path_query(content, '$.fields[*]."856".subfields[*].u') AS "856"
FROM t
WHERE jsonb_path_query_first(content, '$.fields[*]."856".subfields[*].u' )::text ilike '%domain%';
输出:
id
001
856
81be1acf-11df-4d13-a5c6-4838e3a808ee
"mig00004139229"
"https://some.domain.com"
更新: 因为 Postgresql 版本早于 12。
你可以试试这样的方法,但我认为一定有更好的方法:
SELECT
t.id,
max(sq1."001") AS "001",
max(sq2."856") AS "856"
FROM t
INNER JOIN (SELECT id, (jsonb_array_elements(content -> 'fields') -> '001')::text AS "001" FROM t) AS sq1 ON t.id = sq1.id
INNER JOIN (SELECT id, (jsonb_array_elements(jsonb_array_elements(content -> 'fields') -> '856' -> 'subfields') -> 'u')::text AS "856" FROM t) AS sq2 ON t.id = sq2.id
WHERE sq2."856" ilike '%domain%'
GROUP BY t.id;
我必须查询一个包含 2 列的 table,id 和 content。 Id 只是一个 uuid,内容栏看起来像
{
"fields": [
{
"001": "mig00004139229"
},
{
"856": {
"ind1": " ",
"ind2": " ",
"subfields": [
{
"u": "https://some.domain.com"
},
{
"z": "some text"
}
]
}
},
{
"999": {
"subfields": [
{
"i": "81be1acf-11df-4d13-a5c6-4838e3a808ee"
},
{
"s": "3a6aa357-8fd6-4451-aedc-13453c1f2296"
}
]
}
}
]
}
我需要 select 子字段“u”域与字符串“domain.com”匹配的 id、001 和 856 元素,因此输出将是
id | 001 | 856 |
---|---|---|
81be1acf-11df-4d13-a5c6-4838e3a808ee | mig00004139229 | https://some.domain.com |
如果这是一个平面 table,查询将对应于“select id, 001, 856 from table where 856 like '%domain.com%' “
我可以根据我需要的条件 select 单独的列,但它们出现在单独的行中,除了在常规 select 语句中与任何其他单独字段一起出现的 id。我怎样才能让其他字段出现在同一行中,因为它是同一记录的一部分?
不幸的是,我的 postgres 版本不支持 jsonb_path_query,所以我一直在尝试以下方法:
SELECT id, jsonb_array_elements(content -> 'fields') -> '001',
jsonb_array_elements(content -> 'fields') -> '856' -> 'subfields'
FROM
mytable
WHERE....
此方法 returns 我需要的数据,但各个元素到达单独的行,第一列中带有 id,每个元素都为 null,既不是 001 也不是 856,例如
id | 001 | 856 |
---|---|---|
id_for_first_record | 001_first_record | null |
id_for_first_record | null | null |
id_for_first_record | null | null |
id_for_first_record | null | 856_first_record |
id_for_second_record | 001_second_record | null |
id_for_second_record | null | null |
id_for_second_record | null | null |
id_for_second_record | null | 856_second_record |
可用,但笨重,所以我正在寻找更好的东西
我想我的查询可以帮到你。有多种方法可以解决这个问题,我不确定这是否是最好的方法。
我将 jsonb_path_query()
函数与指定 JSON
值的路径一起使用。
SELECT
id,
jsonb_path_query(content, '$.fields[*]."001"') AS "001",
jsonb_path_query(content, '$.fields[*]."856".subfields[*].u') AS "856"
FROM t
WHERE jsonb_path_query_first(content, '$.fields[*]."856".subfields[*].u' )::text ilike '%domain%';
输出:
id | 001 | 856 |
---|---|---|
81be1acf-11df-4d13-a5c6-4838e3a808ee | "mig00004139229" | "https://some.domain.com" |
更新: 因为 Postgresql 版本早于 12。
你可以试试这样的方法,但我认为一定有更好的方法:
SELECT
t.id,
max(sq1."001") AS "001",
max(sq2."856") AS "856"
FROM t
INNER JOIN (SELECT id, (jsonb_array_elements(content -> 'fields') -> '001')::text AS "001" FROM t) AS sq1 ON t.id = sq1.id
INNER JOIN (SELECT id, (jsonb_array_elements(jsonb_array_elements(content -> 'fields') -> '856' -> 'subfields') -> 'u')::text AS "856" FROM t) AS sq2 ON t.id = sq2.id
WHERE sq2."856" ilike '%domain%'
GROUP BY t.id;