Получить максимальное значение в столбце через запятую - PullRequest
0 голосов
/ 24 августа 2018

Как получить максимум для значений, разделенных запятыми в столбце Original_Ids, и получить максимальное значение в одном столбце и оставшиеся идентификаторы в другом столбце.

|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 голосов
/ 25 августа 2018

SQL Fiddle

Вы можете использовать оконную функцию (https://www.postgresql.org/docs/current/static/tutorial-window.html), чтобы получить максимальный элемент для необъявленного массива. После этого вы можете повторно объединить элементы и удалить вычисленныемаксимальное значение из массива.

Результат:

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 раньше.

Примечание:

Было бы лучше использовать идентификатор для адресации столбцов /массивы вместо исходной строки, как в SQL Fiddle с идентификаторами

0 голосов
/ 25 августа 2018

Если вы установите расширение 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

Но вы не должны хранить значения, разделенные запятыми, чтобы начать с

0 голосов
/ 25 августа 2018

Благодаря превосходным возможностям манипулирования массивами в 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(), но у нас были возможные накладные расходы регулярного выражения и нам все еще приходилось преобразовывать массив в набор).

Но, тем не менее, вы просто (почти) никогда не должны использовать списки (или массивы) с разделителями. Использовать таблицу, это (почти) всегда лучший вариант.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...