5

I know that postgres does not have group_concat, but I want to emulate it for strings by using string_agg (or any other way that works).

I need to have the function called group_concat because of an inability to change legacy code.

How can I do this?

For what its worth, I also tried implementing group_concat using regular concat, and ran into an error there as well:

CREATE AGGREGATE group_concat (text) (sfunc = concat, stype=text)

error:

"function concat(text,text) does not exist"

6
  • 1
    postgresql.org/docs/current/static/sql-createfunction.html. However, I would recommend that you change the application rather than the database. Commented Feb 10, 2017 at 12:40
  • @GordonLinoff See update. Its not possible for policy reasons, though trust me, I would prefer that Commented Feb 10, 2017 at 12:41
  • @soandos: I don't think you have a choice. You might get away with simulating group_concat() but the MySQL syntax deviates in so many areas from standard SQL and the one used by Postgres that you won't get far with keeping the existing SQL statements as they are. The first things that come to mind are date or interval literals, the strange (not to say broken) "boolean" handling in MySQL or implicit type casts. Commented Feb 10, 2017 at 13:16
  • @a_horse_with_no_name I only need to define this for strings. I don't care about any other types Commented Feb 10, 2017 at 13:17
  • I am not talking about group_concat() for other types. I am talking about the huge differences in syntax between Postgres and MySQL. I can't imagine that you will succeed in keeping SQL statements written for MySQL without any changes in your code when you run that against Postgres. It simply won't work. Commented Feb 10, 2017 at 13:19

1 Answer 1

5
-- drop aggregate if exists group_concat(text);
CREATE AGGREGATE group_concat(text) (
  SFUNC=textcat,
  STYPE=text
);

select group_concat(x) from unnest('{a,b,c,d}'::text[]) as x;

textcat is the function used internally by the || operator:

CREATE OPERATOR ||(
  PROCEDURE = textcat,
  LEFTARG = text,
  RIGHTARG = text);

Update

To make the comma as the separator:

--drop aggregate if exists group_concat(text);
--drop function if exists group_concat_trans(text, text);

create or replace function group_concat_trans(text, text)
  returns text
  language sql
  stable as 
$$select concat($1,case when $1 is not null and $2 is not null then ',' end,$2)$$;

create aggregate group_concat(text) (
  sfunc=group_concat_trans,
  stype=text);

select group_concat(x) from unnest(array['a','b','c',null,'d']) as x;
╔══════════════╗
║ group_concat ║
╠══════════════╣
║ a,b,c,d      ║
╚══════════════╝
Sign up to request clarification or add additional context in comments.

10 Comments

I don't seem to be getting the comma in between the values. Is there a way to make that passed in?
@soandos . . . You could have the function default to using a comma, but you can't implement the separator syntax in Postgres.
@GordonLinoff how can I have it default to comma then?
@soandos You did not mention about comma. In this case you should to define yet another function. Answer updated.
@soandos PS Define the function as stable to make it faster.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.