В настоящее время не существует никакого синтаксиса для доступа к записи анонимного типа, кроме как через синтаксис вызова функции или через hstore. Это прискорбно, но вряд ли это можно будет исправить в спешке, если только кто-то действительно заботится, чтобы это произошло. Есть другие приоритеты.
У вас есть три варианта обхода:
CREATE TYPE
Проблема с записями анонимного типа. Так что сделайте это не анонимным. К сожалению, это возможно только до того, как запись станет анонимным; в настоящее время вы не можете преобразовать record
в тип пользователя. Итак, вам нужно сделать:
CREATE TYPE some_t AS (id integer, cc text);
WITH test AS (
SELECT array_agg(t::some_t) as x FROM (
SELECT 1111 as id, 'aaaaa' as cc
) AS t
) SELECT x[1].id FROM test;
Обратите внимание на приведение вывода подзапроса к some_t
перед агрегированием.
Я не могу сказать, что понимаю, почему это приведение не может быть выполнено после индексации массива.
hstore
Как обычно, hstore
приходит на помощь, когда решает сложные типовые задачи.
regress=> WITH test AS (
SELECT array_agg(t) as x FROM (
SELECT 1111 as id, 'aaaaa' as cc
) AS t
) SELECT hstore(x[1])->'id' FROM test;
?column?
----------
1111
(1 row)
Вам нужно расширение hstore
, и я уверен, что оно неэффективно, но работает. Это основано на hstore
поддержке создания hstore из анонимных записей, которые были добавлены для поддержки NEW
и OLD
в триггерах, что было проблемой в прошлом.
Функция обертки?
Оказывается, вы не можете обойти это с помощью простой функции-оболочки, позволяющей указать тип на сайте вызова:
regress=> CREATE OR REPLACE FUNCTION identity(record) RETURNS record AS $$
SELECT $1;
$$ LANGUAGE sql IMMUTABLE;
ERROR: SQL functions cannot have arguments of type record
поэтому вам придется использовать процедурный язык с более высокими накладными расходами, после чего вы можете использовать вместо него hstore, это будет быстрее и проще.
Сделать лучше?
Итак, это все немного некрасиво. Невозможно напрямую проиндексировать поле из анонимной записи, поскольку оно может не существовать и его тип невозможно определить. Но нет причин, по которым мы не можем использовать функцию системы типов, которая позволяет нам возвращать record
из функции и указывать ее тип на стороне вызывающей стороны, чтобы также делать это в приведениях.
Должна быть возможность сделать так, чтобы PostgreSQL поддерживал что-то вроде:
WITH test AS (
SELECT array_agg(t) as x FROM (
SELECT 1111 as id, 'aaaaa' as cc
) AS t
) SELECT (x[1] AS some_t(id integer, cc text)).id FROM test;
это просто потребовало бы соответствующего взлома парсера и способа гарантировать, что он никогда не будет неоднозначно проанализирован в конфликте с псевдонимом столбца.
На самом деле, даже вывод типов мог бы быть возможен, если бы кто-то был готов вложить эту работу и убедить команду в том, что довольно большое количество требуемого времени процессора планировщика запросов того стоит. (вряд ли).
Это раздражающий, но второстепенный момент в системе шрифтов. Если вы хотите, чтобы это изменилось, вам нужно будет пошуметь над pgsql-general и сопровождать этот шум готовностью проделать реальную работу по устранению проблемы. Это может включать в себя изучение внутренней сущности системы типов PostgreSQL больше, чем вы когда-либо хотели, изучение удовольствия от «обратной совместимости» и ведение разочаровывающих споров вокруг и вокруг. Добро пожаловать в открытый исходный код!
person
Craig Ringer
schedule
21.01.2014
hstore
и таким образом извлечь из него поля, но это не совсем то, что вам нужно. Псевдотип PostgreSQLrecord
немного ограничен - в частности, нет анонимного приведения записей, напримерCAST(somerecord AS t(x integer, y text))
не работает. - person Craig Ringer   schedule 21.01.2014