获取列中逗号分隔值的最大值

时间:2018-08-24 20:01:15

标签: sql postgresql

如何在Original_Ids列中获取逗号分隔值的最大值,并在一个列中获取最大值,而在另一列中获取其余ID。

|Original_Ids   | Max_Id| Remaining_Ids |
|123,534,243,345| 534   | 123,234,345 |

Upadte - 如果我已经有了Max_id,只需要下面的方程式?

  Remaining_Ids = Original_Ids - Max_id 

谢谢

3 个答案:

答案 0 :(得分:1)

由于Postgres中数组处理的出色可能性,可以通过将字符串转换为数组然后从那里转换为集合来相对容易地实现。

然后可以对该集合进行常规查询。使用max()可以选择最大值,使用EXCEPT ALL可以从集合中删除最大值。

然后可以将集合转换为数组并使用array_to_string(),然后可以将数组再次转换为定界字符串。

SELECT ids original_ids,
       (SELECT max(un.id::integer)
               FROM unnest(string_to_array(ids,
                                           ',')) un(id)) max_id,
       array_to_string(ARRAY((SELECT un.id::integer
                                     FROM unnest(string_to_array(ids,
                                                                 ',')) un(id)
                              EXCEPT ALL
                              SELECT max(un.id::integer)
                                     FROM unnest(string_to_array(ids,
                                                                 ',')) un(id))),
                       ',') remaining_ids
       FROM elbat;

另一种选择是regexp_split_to_table(),它可以直接生成一个集合(或regexp_split_to_array(),但比起我们可能有正则表达式的开销,仍然必须将数组转换为集合)。

但是,尽管如此,您应该(几乎)永远不要使用定界列表(也不能使用数组)。使用表,那(几乎)总是最好的选择。

答案 1 :(得分:1)

SQL Fiddle

您可以使用窗口函数(https://www.postgresql.org/docs/current/static/tutorial-window.html)来获取每个未嵌套数组的max元素。之后,您可以重新聚合元素并从数组中删除计算出的最大值。

结果:

a                     max_elem     remaining
123,534,243,345       534          123,243,345
3,23,1                23           3,17
42                    42           
56,123,234,345,345    345          56,123,234

此查询只需要进行一次拆分/嵌套,也只需进行一次最大计算。

SELECT 
    a,
    max_elem,
    array_remove(array_agg(elements), max_elem) as remaining      -- C
FROM (
    SELECT 
        *, 
        MAX(elements) OVER (PARTITION BY a) as max_elem           -- B
    FROM (
        SELECT 
            a, 
            unnest((string_to_array(a, ','))::int[]) as elements  -- A
        FROM arrays
    )s
)s
GROUP BY a, max_elem

A:string_to_array将字符串列表转换为数组。由于将数组视为字符串数组,因此需要通过添加::int[]将其强制转换为整数数组。 unnest()将所有数组元素扩展为自己的行。

B:窗口函数MAX给出单个数组的最大值为max_elem

C:array_agg通过GROUP BY id重新聚集元素。之后,array_remove从数组中删除max_elem的值。

如果您不喜欢将它们存储为纯数组,而是再次存储为字符串列表,则可以添加array_to_string。但是我不建议这样做,因为您的数据是整数数组而不是字符串。对于每个进一步的计算,您都需要此字符串强制转换。更好的方法(如@stickybit所述)不是将元素存储为数组,而是存储为未嵌套的数据。如您所见,几乎每个操作都应该在之前执行unnest

注意:

最好使用ID处理列/数组,而不要像SQL Fiddle with IDs

中那样使用原始字符串。

答案 2 :(得分:1)

如果您安装扩展名为intarray,则非常简单。

首先,您需要创建扩展名(您必须是超级用户才能这样做):

create extension intarray;

然后您可以执行以下操作:

select original_ids, 
       original_ids[1] as max_id,
       sort(original_ids - original_ids[1]) as remaining_ids
from (       
  select sort_desc(string_to_array(original_ids,',')::int[]) as original_ids
  from bad_design
) t

但是您不应该存储逗号分隔的值