从数组创建字符串

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}

arrayofparentsinteger[] 类型,它包含该行的 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]
  ), '->'
) ;

live example Sqlfiddle

或使用外连接结合任何:

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

live example Sqlfiddle

这些查询中的每一个都适用于单个 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 值。

SQL Fiddle.

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;