Postgres aggregate row to string

时间:2015-07-31 20:29:48

标签: postgresql

If I have a following query:

SELECT 'a' AS a, 1 AS b, CURRENT_DATE AS c;

It's possible to aggregate row to string as:

SELECT concat_ws(', ', a, b, c) FROM (
    SELECT 'a' AS a, 1 AS b, CURRENT_DATE AS c
) AS T;

-- Result: "a, 1, <CURRENT DATE>"

But what I can't seem to find - if there is already existing function in postgres (version 9.3 or 9.4) that will produce the same result as above, but operating with a "*"

--
-- Something like:
--
-- some_function(<separator>,  *) - ???
--
SELECT some_function(', ', *) FROM (
    SELECT 'a' AS a, 1 AS b, CURRENT_DATE AS c
) AS T;

-- so the result would be - "a, 1, <CURRENT DATE>"

Thanks for any help.

1 个答案:

答案 0 :(得分:1)

If you convert the row to a hstore, you can do that:

select array_to_string(avals(hstore(x)), ', ')
from (
  SELECT 'a' AS a, 1 AS b, CURRENT_DATE AS c
) x

hstore(x) will convert all column values to strings and then put them into the hstore. avals then extracts the values as a string array, and array_to_string converts it into a comma separated list.

To do that for a regular table, you need to pass the table name, not *

select array_to_string(avals(hstore(foobar)), ', ')
from foobar;

If you don't want to (or can't) install the hstore extension, you can do this with the JSON function although it requires one more level of nesting:

select string_agg(value, ', ') 
from (
  select (json_each_text(row_to_json(x1))).value
  from (
    SELECT 'a' AS a, 1 AS b, CURRENT_DATE AS c
  ) x1
) x2

Or to get the data from a table:

select string_agg(value, ', ') 
from (
  select (json_each_text(row_to_json(foobar))).value
  from foobar
) x

If you want you can "hide" this in a function:

create or replace function concat_record(p_data anyelement, p_delim text)
  returns text
as $$
   select array_to_string(avals(hstore(p_data)), p_delim);
$$
language sql;

And then you can do:

select concat_record(foobar, ', ')
from foobar;

Unrelated but: you don't need the select for the dummy data:

select *
from (
  values ('a', 1, CURRENT_DATE)
) as x (a,b,c);

Is a bit shorter to write - especially if you have more than one row.

select *
from (
  values 
     ('a', 1, CURRENT_DATE), 
     ('x', 2, date  '2015-07-01')
) as x (a,b,c);