PostgreSQL: как получить доступ к столбцу анонимной записи

У меня есть проблема, над которой я работаю. Ниже приведен упрощенный запрос, показывающий проблему:

WITH the_table AS (
    SELECT a, b 
    FROM (VALUES('data1', 2), ('data3', 4), ('data5', 6)) x (a, b)
), my_data AS (
    SELECT 'data7' AS c, array_agg(ROW(a, b)) AS d
    FROM the_table
)
SELECT c, d[array_upper(d, 1)]
FROM my_data

В разделе моих данных вы заметите, что я создаю массив из нескольких строк, и массив возвращается в одной строке с другими данными. Этот массив должен содержать информацию как для a, так и для b, а также связывать два значения вместе. Казалось бы, имеет смысл использовать анонимную строку или запись (я хочу избежать фактического создания составного типа).

Все это работает хорошо, пока мне не нужно начать извлекать данные обратно. В приведенном выше примере мне нужно получить доступ к последней записи в массиве, что легко сделать с помощью array_upper, но затем мне нужно получить доступ к значению в том, что раньше было столбцом b, что я не могу понять, как это сделать.

По сути, прямо сейчас возвращается приведенный выше запрос:

"data7";"(data5,6)"

И мне нужно вернуться

"data7";6

Как я могу это сделать?

ПРИМЕЧАНИЕ. Хотя в приведенном выше примере я использую текст и целые числа в качестве типов для своих данных, они не являются фактическими конечными типами, а скорее используются для упрощения примера.

ПРИМЕЧАНИЕ. Здесь используется PostgreSQL 9.2.

РЕДАКТИРОВАТЬ: Для уточнения, что-то вроде SELECT 'data7', 6 - это не то, что мне нужно. Представьте, что the_table на самом деле извлекает из таблиц базы данных, а не оператор WITH, который я вставил для удобства, и я не всегда знаю, какие данные находятся в таблице.

Другими словами, я хочу иметь возможность сделать что-то вроде этого:

SELECT c, (d[array_upper(d, 1)]).b
FROM my_data

И верните это:

"data7";6

По сути, как только я поместил что-то в анонимную запись с помощью функции row(), как мне получить это обратно? Как разделить часть 'data5' и часть 6, чтобы они не возвращались в один столбец?

Другой пример:

SELECT ROW('data5', 6)

заставляет «data5» и 6 возвращаться в один столбец. Как мне взять этот столбец и разбить его на два исходных?

Я надеюсь, что это проясняет


person Trevor Young    schedule 06.12.2014    source источник
comment
Зачем вам нужно использовать массивы для того, что выглядит как простой запрос агрегации?   -  person Gordon Linoff    schedule 06.12.2014
comment
Это упрощенный пример, чтобы сделать мой вопрос более понятным. Полный запрос использует рекурсивный оператор with для сбора данных (включая строки с массивами), а затем я использую DISTINCT ON для одного столбца и ORDER BY для другого столбца, чтобы исключить ненужные данные, сгенерированные из рекурсивного запроса. Все это прекрасно работает, если, например, мне нужны данные только из столбца a, но мне нужны и a, и b, и я не могу потерять их связь. Если бы я использовал pgsql 9.4, я бы просто имел a и b в отдельных массивах, а затем использовал несколько столбцов без вложенности, которые он должен позже повторно связать a и b. Но у меня 9.2.   -  person Trevor Young    schedule 06.12.2014
comment
Страница с похожим вопросом с ответом, который не работает в этом случае, находится здесь: postgresql.org/message-id/   -  person Trevor Young    schedule 06.12.2014
comment
@TrevorYoung: Можете ли вы опубликовать реальный запрос и некоторые реальные данные? Вот так читатели блуждают в темноте. Ваш OP касается строк в массиве, ваш комментарий выше касается массива в строке. То, что вы опубликовали до сих пор, имеет довольно тривиальное решение SELECT 'data7', 6;, которое, очевидно, не то, что вы ищете...   -  person Patrick    schedule 06.12.2014
comment
Мне придется вытащить запрос в следующий раз, когда я буду на работе, но смысл примера в том, чтобы сделать его простым. Мой вопрос заключается в том, как мне вернуть столбец из объекта, созданного функцией row()?   -  person Trevor Young    schedule 06.12.2014
comment
Если бы я использовал pgsql 9.4, я бы просто имел a и b в отдельных массивах Почему вы не можете сделать это в 9.2?   -  person Clodoaldo Neto    schedule 06.12.2014
comment
Невложенность нескольких аргументов — это новая функция версии 9.4. Читайте об этом здесь: michael.otacoo.com/postgresql-2/   -  person Trevor Young    schedule 07.12.2014


Ответы (2)


Если вы можете установить расширение hstore:

with the_table as (
    select a, b
    from (values('data1', 2), ('data3', 4), ('data5', 6)) x (a, b)
), my_data as (
    select 'data7' as c, array_agg(row(a, b)) as d
    from the_table
)
select c, (avals(hstore(d[array_upper(d, 1)])))[2]
from my_data
;
   c   | avals 
-------+-------
 data7 | 6
person Clodoaldo Neto    schedule 06.12.2014
comment
Это в основном именно то, что я ищу, за исключением того факта, что вам нужно загрузить расширение, чтобы оно заработало. Я не знаю, я просто думаю, что это глупо, что вы можете построить структуру, которую вы не можете разобрать, если не используете расширение. В любом случае, я сейчас проголосую за вас, и если никто не предложит более нативное решение (без расширений), я приму ваш ответ. - person Trevor Young; 08.12.2014
comment
Вопрос для вас. Вы знаете, как метод avals помещает два разных типа данных в один и тот же массив? Большая часть информации в Интернете говорит, что у вас не может быть массива с разными типами, но авалы, похоже, позволяют это. - person Trevor Young; 08.12.2014
comment
Подождите, я нашел ответ на свой вопрос там. Он превращает все в текст и использует текстовый массив. В моем примере это работает с текстом и целыми числами, но, например, может стать сложнее работать с составными типами. Я бы предпочел найти что-то, что поддерживает типы, если это вообще возможно. - person Trevor Young; 08.12.2014

Это просто очень быстрое решение похожей проблемы, а не ответ на ваш вопрос. Похоже, это одно из направлений идентификации столбцов.

with x as (select 1 a, 2  b union all values (1,2),(1,2),(1,2))
select a from x;
person Damien Sawyer    schedule 23.07.2020