【问题标题】:Coalesce multiple levels based on type and "parent"根据类型和“父级”合并多个级别
【发布时间】:2020-07-05 09:08:56
【问题描述】:

假设我有一个看起来像这样的数据库

id |Name | Type | budget | parentId | 
1 | a   |  1   | 5000   |  null    |
2 | b1  |  2   | 2200   | 1        |
3 | c2  |  2   | 2800   | 1        | 
4 | b_1 |  3   | 1000   | 2        |
5 | b_2 |  3   | 1200   | 2        |
6 | c_1 |  3   | 1600   | 3        |
7 | c_2 |  3   | 1200   | 3        |

我想要的输出是这样的:

Name | Type | Budget | ParentName
a   |   1  | 5000   |   null
b1  |   2  | 2200   |   a
b_1 |   3  | 1000   |   b1
b_2 |   3  | 1200   |   b1
c1  |   2  | 2800   |   a
c_1 |   3  | 1600   |   c1
c_2 |   3  | 1200   |   c1

我该怎么做呢?

需求本质上是按父类型分组的,由类型 1 或 null 父 id 表示。从那里首先将类型 2 分组到类型 1 下方,然后将类型 2 的所有子类型 3 分组为每个类型 2 下方的父级。

这有点像一场噩梦,我尝试使用 COALESCE,但在尝试使用它时对语法有点困惑

1 
  2
    3
    3
  2
    3
    3
    3
  2 .. 

等等

这里的任何帮助都会很有用。

注意:类型 1 永远不会有父对象,类型 2 将始终具有类型 1 的父对象,类型 3 将始终具有类型 2 的父对象。

谢谢,

【问题讨论】:

  • 这个层次结构有多少层?
  • @forpas 仅 3.

标签: sql postgresql


【解决方案1】:

对于这个示例数据,只有 3 个级别,您可以使用条件排序:

select t1.name, t1.type, t1.budget, t2.Name ParentName 
from tablename t1 left join tablename t2 
on t2.id = t1.parentid
order by 
  case when t2.parentid is null then t1.id else t1.parentid end,
  t1.id

请参阅demo
结果:

| name | type | budget | parentname |
| ---- | ---- | ------ | ---------- |
| a    | 1    | 5000   |            |
| b1   | 2    | 2200   | a          |
| b_1  | 3    | 1000   | b1         |
| b_2  | 3    | 1200   | b1         |
| c1   | 2    | 2800   | a          |
| c_1  | 3    | 1600   | c1         |
| c_2  | 3    | 1200   | c1         |

【讨论】:

    【解决方案2】:

    您可以将表连接到自身以获得所需的输出:

    SELECT S1.Name, S1.Type, S1.Budget, S2.Name as ParentName FROM some_data S1 LEFT JOIN some_data S2 ON S1.parentId = S2.id;
    

    产生以下输出:

    Name|Type|Budget|ParentName
    a   |   1|  5000| null
    b1  |   2|  2200|    a
    c2  |   2|  2800|    a
    b_1 |   3|  1000|   b1
    b_2 |   3|  1200|   b1
    c_1 |   3|  1600|   c2
    c_2 |   3|  1200|   c2
    

    【讨论】:

    • 有点接近,但我希望完全扩展每个层次结构,以便 b_1 / b_2 嵌套在 b1 下而不是下面,因为我可以使用 group by 来实现上述结果。
    • 结果不符合预期的问题是什么?
    • 查看@forpas 的解决方案。
    • 如果您需要三个以上的级别,并且这是一种常见的查询模式,请考虑使用图形数据库来存储数据。如果您想留在 PostgreSQL 中,请考虑编写一个 PL/pgSQL 函数来为每条记录生成值,然后您可以对其进行排序。这可以在读取时应用,也可以作为写入时的触发函数。
    猜你喜欢
    • 2021-01-06
    • 2021-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多