从数组创建字符串
Create string from array
我在 PostgreSQL 中有一个 table,其中包含:
id name arrayofparents
1 First
2 Second {1}
3 Second_Sec {1,2}
4 Third {1,2,3}
5 Second_A {1}
6 Other
7 Trash {6}
arrayofparents
是 integer[]
类型,它包含该行的 parents 记录列表,顺序正确。
id=4
parents 分别是:First
然后 Second
然后 Second_sec
我如何编写查询以针对任何给定的 ID 生成它的 parents 名称的字符串?
例如:
id=3
: First->Second
.
id=4
: First->Second->Second_sec
.
id=7
: Other
.
编辑:
如果可能的话,我希望请求的 ID name
始终出现。
id=3
: First->Second->Second_sec
.
id=4
: First->Second->Second_sec->Third
.
id=7
: Other->Trash
.
id=6
: Other
.
如果您只想直接 parents(而不是 grandparents),那么像这样的方法应该可行:
SELECT c.id, c.name, string_agg(p.name, '->') AS parentnames
FROM yourtable AS c
LEFT JOIN yourtable AS p ON p.id = ANY c.parents
GROUP BY c.id, c.name
您可以组合多个操作,例如 generate_subscripts 和数组来获得结果:
with mtab as (
SELECT id, name, array_append(arrayofparents,id) as arrayofparents,
generate_subscripts(array_append(arrayofparents, id), 1) AS p_id FROM tab where id=2
)
select distinct array_to_string(
array(
select tab.name from tab join mtab t on tab.id=t.arrayofparents[t.p_id]
), '->'
) ;
或使用外连接结合任何:
SELECT coalesce(string_agg(p.name, '->') || '->' || t.name, t.name) AS parentnames
FROM tab AS t
LEFT JOIN tab AS p ON p.id = ANY(t.arrayofparents)
where t.id =7
GROUP BY t.id, t.name
这些查询中的每一个都适用于单个 ID 以及整个 table。
您可以 return 仅路径/完整路径或所有其他列。
SELECT t.*, concat_ws('->', t1.path, t.name) AS full_path
FROM tbl t
LEFT JOIN LATERAL (
SELECT string_agg(t1.name, '->' ORDER BY i) AS path
FROM generate_subscripts(t.arrayofparents, 1) i
JOIN tbl t1 ON t1.id = t.arrayofparents[i]
) t1 ON true
WHERE t.id = 4; -- optional
或者,您可以将 ORDER BY
移动到子查询 - 可能会快一点:
SELECT concat_ws('->', t1.path, t.name) AS full_path
FROM tbl t, LATERAL (
SELECT string_agg(t1.name, '->') AS path
FROM (
SELECT t1.name
FROM generate_subscripts(t.arrayofparents, 1) i
JOIN tbl t1 ON t1.id = t.arrayofparents[i]
ORDER BY i
) t1
) t1
WHERE t.id = 4; -- optional
由于聚合发生在 LATERAL
子查询中,我们不需要在外部查询中执行 GROUP BY
步骤。
我们也不需要 LEFT JOIN LATERAL ... ON true
保留所有 arrayofparents
为 NULL 或空的行,因为 LATERAL
子查询 always return由于聚合函数,我们排成一行。
LATERAL
需要 Postgres 9.3。
使用 concat_ws()
忽略串联中可能的 NULL 值。
WITH OTDINALITY
使它在 Postgres 中更简单和更快 9.4:
SELECT t.*, concat_ws('->', t1.path, t.name) AS full_path
FROM tbl t, LATERAL (
SELECT string_agg(t1.name, '->' ORDER BY ord) AS path
FROM unnest(t.arrayofparents) WITH ORDINALITY a(id,ord)
JOIN tbl t1 USING (id)
) t1
WHERE t.id = 4;
详细解释:
- PostgreSQL unnest() with element number
pg 9.3 的 UNION ALL
变体
SELECT t1.full_path
FROM tbl t, LATERAL (
SELECT string_agg(name, '->') AS full_path
FROM (
(
SELECT name
FROM generate_subscripts(t.arrayofparents, 1) i
JOIN tbl ON id = t.arrayofparents[i]
ORDER BY i
)
UNION ALL SELECT t.name
) t1
) t1
WHERE t.id = 4;
我在 PostgreSQL 中有一个 table,其中包含:
id name arrayofparents
1 First
2 Second {1}
3 Second_Sec {1,2}
4 Third {1,2,3}
5 Second_A {1}
6 Other
7 Trash {6}
arrayofparents
是 integer[]
类型,它包含该行的 parents 记录列表,顺序正确。
id=4
parents 分别是:First
然后 Second
然后 Second_sec
我如何编写查询以针对任何给定的 ID 生成它的 parents 名称的字符串?
例如:
id=3
: First->Second
.
id=4
: First->Second->Second_sec
.
id=7
: Other
.
编辑:
如果可能的话,我希望请求的 ID name
始终出现。
id=3
: First->Second->Second_sec
.
id=4
: First->Second->Second_sec->Third
.
id=7
: Other->Trash
.
id=6
: Other
.
如果您只想直接 parents(而不是 grandparents),那么像这样的方法应该可行:
SELECT c.id, c.name, string_agg(p.name, '->') AS parentnames
FROM yourtable AS c
LEFT JOIN yourtable AS p ON p.id = ANY c.parents
GROUP BY c.id, c.name
您可以组合多个操作,例如 generate_subscripts 和数组来获得结果:
with mtab as (
SELECT id, name, array_append(arrayofparents,id) as arrayofparents,
generate_subscripts(array_append(arrayofparents, id), 1) AS p_id FROM tab where id=2
)
select distinct array_to_string(
array(
select tab.name from tab join mtab t on tab.id=t.arrayofparents[t.p_id]
), '->'
) ;
或使用外连接结合任何:
SELECT coalesce(string_agg(p.name, '->') || '->' || t.name, t.name) AS parentnames
FROM tab AS t
LEFT JOIN tab AS p ON p.id = ANY(t.arrayofparents)
where t.id =7
GROUP BY t.id, t.name
这些查询中的每一个都适用于单个 ID 以及整个 table。
您可以 return 仅路径/完整路径或所有其他列。
SELECT t.*, concat_ws('->', t1.path, t.name) AS full_path
FROM tbl t
LEFT JOIN LATERAL (
SELECT string_agg(t1.name, '->' ORDER BY i) AS path
FROM generate_subscripts(t.arrayofparents, 1) i
JOIN tbl t1 ON t1.id = t.arrayofparents[i]
) t1 ON true
WHERE t.id = 4; -- optional
或者,您可以将 ORDER BY
移动到子查询 - 可能会快一点:
SELECT concat_ws('->', t1.path, t.name) AS full_path
FROM tbl t, LATERAL (
SELECT string_agg(t1.name, '->') AS path
FROM (
SELECT t1.name
FROM generate_subscripts(t.arrayofparents, 1) i
JOIN tbl t1 ON t1.id = t.arrayofparents[i]
ORDER BY i
) t1
) t1
WHERE t.id = 4; -- optional
由于聚合发生在 LATERAL
子查询中,我们不需要在外部查询中执行 GROUP BY
步骤。
我们也不需要 LEFT JOIN LATERAL ... ON true
保留所有 arrayofparents
为 NULL 或空的行,因为 LATERAL
子查询 always return由于聚合函数,我们排成一行。
LATERAL
需要 Postgres 9.3。
使用 concat_ws()
忽略串联中可能的 NULL 值。
WITH OTDINALITY
使它在 Postgres 中更简单和更快 9.4:
SELECT t.*, concat_ws('->', t1.path, t.name) AS full_path
FROM tbl t, LATERAL (
SELECT string_agg(t1.name, '->' ORDER BY ord) AS path
FROM unnest(t.arrayofparents) WITH ORDINALITY a(id,ord)
JOIN tbl t1 USING (id)
) t1
WHERE t.id = 4;
详细解释:
- PostgreSQL unnest() with element number
pg 9.3 的 UNION ALL
变体
SELECT t1.full_path
FROM tbl t, LATERAL (
SELECT string_agg(name, '->') AS full_path
FROM (
(
SELECT name
FROM generate_subscripts(t.arrayofparents, 1) i
JOIN tbl ON id = t.arrayofparents[i]
ORDER BY i
)
UNION ALL SELECT t.name
) t1
) t1
WHERE t.id = 4;