Обсуждение: [GENERAL] How to stop array_to_json from interpolating column names thatweren't there

Поиск
Список
Период
Сортировка

[GENERAL] How to stop array_to_json from interpolating column names thatweren't there

От
Guyren Howe
Дата:
9.6

I’ve a view that shows information about schemas:

 SELECT schemata.catalog_name,
    schemata.schema_name,
    ('/'::text || (schemata.schema_name)::text) AS schema_name_address
   FROM information_schema.schemata
  ORDER BY schemata.catalog_name, schemata.schema_name

Fine. I now want to turn that result set into a JSON array. I can do this:

SELECT
ARRAY_AGG(foo) AS foos
FROM (
SELECT
row_to_json(schemata_)
FROM
schemata_)
AS
foo
and I get this:

{“(\”{\"\"catalog_name\"\":\"\"ds2_development\"\",\"\"schema_name\"\":\"\"admin\"\",\"\"schema_name_address\"\":\"\"/admin\"\"}\")","(\"

which is great. I have an array of perfect JSON objects. Now I just need to turn that into a single JSON object. But when I do the obvious:

SELECT array_to_json(
SELECT
ARRAY_AGG(foo) AS foos
FROM (
SELECT
row_to_json(schemata_)
FROM
schemata_)
AS
foo
)

I get a syntax error. And when I do:

SELECT TO_JSON(foos) FROM (
SELECT
ARRAY_AGG(foo) AS foos
FROM (
SELECT
row_to_json(schemata_)
FROM
schemata_)
AS
foo
) AS bar

Postgres tries to be helpful by interpolating a column name I don’t want (here, row_to_json):

[{“row_to_json":{"catalog_name":"ds2_development","schema_name":"admin","schema_name_address":"/admin"}},{"row_to_json":{"catalog_name":"ds2_development","schema_name":"anon","schema_name_address":"/anon"}},{"row_to_json":

I could fix this in PLV8 a tad inefficiently, but I feel like I ought to be able to do this in pure SQL and there’s some heuristic or Yet Another Weird Corner Case I’m as yet unaware of.

So: can I do this in SQL? How?
Guyren Howe <guyren@gmail.com> writes:
> I have an array of perfect JSON objects. Now I just need to turn that into a single JSON object. But when I do the
obvious:

> SELECT array_to_json(
>         SELECT
>             ARRAY_AGG(foo) AS foos
>         FROM (
>             SELECT
>                 row_to_json(schemata_)
>             FROM
>                 schemata_)
>             AS
>                 foo
> )

> I get a syntax error.

Well, yeah, you're missing parentheses around the scalar sub-select.
(Whether fixing that will give the behavior you want is unclear,
but the syntax error is clear.)

            regards, tom lane


Re: [GENERAL] How to stop array_to_json from interpolating columnnames that weren't there

От
Paul Jungwirth
Дата:
> which is great. I have an array of perfect JSON objects. Now I just need
> to turn that into a single JSON object.

I think you're saying you want it as a single JSON *array*, right? An
object of objects doesn't make sense. Assuming that's right, this seems
to work:

db1=# select json_agg(schemata) from schemata;
                                                  json_agg

----------------------------------------------------------------------------------------------------------

[{"catalog_name":"db1","schema_name":"information_schema","schema_name_address":"/information_schema"},
{"catalog_name":"db1","schema_name":"pg_catalog","schema_name_address":"/pg_catalog"},
{"catalog_name":"db1","schema_name":"pg_temp_1","schema_name_address":"/pg_temp_1"},
{"catalog_name":"db1","schema_name":"pg_toast","schema_name_address":"/pg_toast"},
{"catalog_name":"db1","schema_name":"pg_toast_temp_1","schema_name_address":"/pg_toast_temp_1"},
{"catalog_name":"db1","schema_name":"public","schema_name_address":"/public"}]
(1 row)

Paul


Re: [GENERAL] How to stop array_to_json from interpolating columnnames that weren't there

От
Guyren Howe
Дата:
On Jul 19, 2017, at 20:47 , Paul Jungwirth <pj@illuminatedcomputing.com> wrote:

which is great. I have an array of perfect JSON objects. Now I just need
to turn that into a single JSON object.

I think you're saying you want it as a single JSON *array*, right? An object of objects doesn't make sense. Assuming that's right, this seems to work:

db1=# select json_agg(schemata) from schemata;
                                                json_agg
----------------------------------------------------------------------------------------------------------
[{“catalog_name":"db1","schema_name":"information_schema","schema_name_address":"/information_schema"},

Thanks. Seeking greater understanding, why is json_agg(*) not equivalent?

Re: [GENERAL] How to stop array_to_json from interpolating columnnames that weren't there

От
"David G. Johnston"
Дата:
On Wed, Jul 19, 2017 at 8:53 PM, Guyren Howe <guyren@gmail.com> wrote:
Thanks. Seeking greater understanding, why is json_agg(*) not equivalent?

​Are you referring to the fact that ​this provokes an error?

"select json_agg(*) from schemata;"

The json_agg(expression) function has an arity of 1 (i.e., one input argument only).  If you write:

select schemata from schemata;

you get one column in the output, while:

select * from schemata

results in an output relation having three columns - the "*" expands the composite type in the FROM clause into its component columns in the select-list

json_agg(*) fails since it is not expecting 3 columns (though oddly the error I see in 9.6 indicates its actually looking for a 0-arity function... "function json_agg() does not exist" - which implies that generally one cannot place a * in a function call, even if it would result in a single column.  This may even be documented but I haven't the desire to look right now...)

David J.


"David G. Johnston" <david.g.johnston@gmail.com> writes:
> On Wed, Jul 19, 2017 at 8:53 PM, Guyren Howe <guyren@gmail.com> wrote:
>> Thanks. Seeking greater understanding, why is json_agg(*) not equivalent?

> ​Are you referring to the fact that ​this provokes an error?
> "select json_agg(*) from schemata;"

The reason for that is that we interpret foo(*) as a call to a
zero-argument aggregate, in order to satisfy the spec's insistence
that "count(*)" is the way to invoke the argument-free form of count().
But there's no zero-argument function named json_agg().

I think David's answer was based on interpreting the command as

select json_agg(schemata.*) from schemata;

but that's something entirely different: it results in passing a
single composite-type argument to the function.  Yet again different
is use of * at top level of a SELECT list.

SQL is not the most consistent language in the world to begin with, and
some of these notations are things we inherited from Berkeley PostQUEL
and didn't want to give up, so it's a bit of a mess :-(

            regards, tom lane