【问题标题】:Postgres GROUP BY an array columnPostgres GROUP BY 一个数组列
【发布时间】:2021-02-02 06:07:52
【问题描述】:

我有一份学生和家长的名单,并希望使用学生 ID 将他们分组。拥有共同学生证的父母可以被视为一个家庭,而拥有共同父母证的学生也可以被视为一个家庭。这是一个示例表:

 p_id | parent_name | s_id | student_name |
------------------------------------------|
 1    | John Doe    | 100 |  Mike Doe     |
 3    | Jane Doe    | 100 |  Mike Doe     |
 3    | Jane Doe    | 105 |  Lisa Doe     |
 5    | Will Willy  | 108 |  William Son  |

我希望得到类似的结果:

     parents       |       students         |
-------------------|------------------------|
John Doe, Jane Doe |  Mike Doe, Lisa Doe    |
Will Willy         |  William Son           |

为了实现这一点,我目前正在使用:

SELECT array_agg(parents) AS parents FROM (
    SELECT array_agg(p_id) AS par_ids, array_agg(parent_name) AS parents, student_name, s_id 
    FROM (
        /* sub query */
    )b
    GROUP BY s_id, student_name
    ORDER BY parents ASC
)c
GROUP BY unnest(par_ids)
ORDER BY parents ASC

但我收到一个错误:ERROR: cannot accumulate arrays of different dimensionality。 SQL state: 2202E

我怎样才能达到预期的效果? 上述语句的内部查询返回:

| par_ids |       parents       |  student_name   | s_id |
--------------------------------|------------------------|
| {1,3}   | {John Doe, Jane Doe}|  Mike Doe       | 100  |
| {3}     | {Jane Doe}          |  Lisa Doe       | 105  |
| {5}     | {Will Willy}        |  William Son    | 108  |

现在将这些学生归为家长是我的难题。

【问题讨论】:

    标签: postgresql group-by array-agg


    【解决方案1】:

    我已经在这里做了类似的事情(但有点复杂):https://stackoverflow.com/a/53129510/3984221


    step-by-step demo:db<>fiddle

    SELECT
        array_agg(parent_name) as parents,                -- 4
        array_agg(student_name) as students
    FROM (
        SELECT DISTINCT ON (t.s_id)                       -- 3
            *
        FROM (
            SELECT
                s_id,
                array_agg(p_id) as parents                -- 1
            FROM mytable
            GROUP BY s_id
        ) s JOIN mytable t ON t.p_id = ANY(s.parents)     -- 2
        ORDER BY t.s_id, CARDINALITY(parents) DESC        -- 3
    ) s
    GROUP BY parents
    
    1. 将p_id 值聚合到一个数组中:

      s_id parents
      108 {5}
      105 {3}
      100 {1,3}
    2. 在这个数组上自连接原始表:

      s_id parents p_id parent_name s_id student_name
      100 {1,3} 1 John Doe 100 Mike Doe
      105 {3} 3 Jane Doe 100 Mike Doe
      100 {1,3} 3 Jane Doe 100 Mike Doe
      105 {3} 3 Jane Doe 105 Lisa Doe
      100 {1,3} 3 Jane Doe 105 Lisa Doe
      108 {5} 5 Will Willy 108 William Son
    3. 删除所有重复的学生记录。剩下的应该是p_id数组最完整的记录。这可以使用DISTINCT ON(s_id) 按数组长度降序完成:

      s_id parents p_id parent_name s_id student_name
      100 {1,3} 1 John Doe 100 Mike Doe
      100 {1,3} 3 Jane Doe 105 Lisa Doe
      108 {5} 5 Will Willy 108 William Son
    4. 最后您可以按p_id 数组分组并聚合两个name 列:

      parents students
      {"John Doe","Jane Doe"} {"Mike Doe","Lisa Doe"}
      {"Will Willy"} {"William Son"}

    如果你不想得到一个数组,而是一个字符串列表,你可以使用string_agg(name_colum, ',')而不是array_agg(name_column)

    【讨论】:

    • 谢谢。这真的帮助了我。想不出办法。
    猜你喜欢
    • 2014-09-28
    • 2019-06-05
    • 1970-01-01
    • 2016-08-14
    • 1970-01-01
    • 1970-01-01
    • 2011-09-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多