Seamless replacement to MySQL's GROUP_CONCAT function...

From: "immersive(dot)excel(at)gmail(dot)com" <immersive(dot)excel(at)gmail(dot)com>
To: x3v0-pgsql(at)yahoo(dot)com
Cc: pgsql-general(at)postgresql(dot)org, David Fetter <david(at)fetter(dot)org>
Subject: Seamless replacement to MySQL's GROUP_CONCAT function...
Date: 2013-08-03 21:52:32
Message-ID: 51FD7BA0.1040000@gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-general

<html>
<head>

<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
</head>
<body bgcolor="#FFFFFF" text="#000000">
I needed a GROUP_CONCAT to port some queries to postgres.<br>
<br>
In discussions online, I found repeated advice for rewriting the
queries, but no solid way to formulate the GROUP_CONCAT as a
postgres function. Rewrite perhaps hundreds of queries that happen
to be in the app you're porting? Puh-lease!<br>
<br>
Note: I found some close-but-no cigar aggregates shared online, but
they would not accept integer arguments, nor would they handle the
optionally furnished delimiter. People would suggesting casting the
argument to the pseudo-GROUP_CONCAT. Again: Rewrite perhaps hundreds
of queries?<br>
<br>
And now the formulation of GROUP_CONCAT for postgres that accepts
either integer or string columns, and the optional delimiter:<br>
<br>
<big><big><tt>-- permutation of GROUP_CONCAT parameter types with
delimiter parameter furnished:<br>
CREATE OR REPLACE<br>
FUNCTION GROUP_CONCAT_ATOM(field1 TEXT, field2 TEXT, delimiter
TEXT)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RETURNS TEXT AS $$<br>
BEGIN<br>
IF field1 IS NULL THEN<br>
&nbsp;&nbsp; RETURN field2;<br>
ELSIF field2 IS NULL THEN<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RETURN field1;<br>
ELSE<br>
&nbsp;&nbsp;&nbsp;&nbsp; RETURN field1||delimiter||field2;<br>
END IF;<br>
END;<br>
$$ LANGUAGE plpgsql;<br>
<br>
CREATE OR REPLACE<br>
FUNCTION GROUP_CONCAT_ATOM(field1 TEXT, field2 INT8, delimiter
TEXT)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RETURNS TEXT AS $$<br>
BEGIN<br>
IF field1 IS NULL THEN<br>
&nbsp;&nbsp; IF field2 IS NULL THEN<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RETURN NULL;<br>
&nbsp;&nbsp; ELSE<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RETURN CAST(field2 AS TEXT);<br>
&nbsp;&nbsp; END IF;<br>
ELSIF field2 IS NULL THEN<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RETURN field1;<br>
ELSE<br>
&nbsp;&nbsp;&nbsp;&nbsp; RETURN field1||delimiter||CAST(field2 AS TEXT);<br>
END IF;<br>
END;<br>
$$ LANGUAGE plpgsql;<br>
<br>
CREATE OR REPLACE<br>
FUNCTION GROUP_CONCAT_ATOM(field1 INT8, field2 TEXT, delimiter
TEXT)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RETURNS TEXT AS $$<br>
BEGIN<br>
IF field1 IS NULL THEN<br>
&nbsp;&nbsp; RETURN field2;<br>
ELSIF field2 IS NULL THEN<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IF field1 IS NULL THEN<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RETURN NULL;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ELSE<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RETURN CAST(field1 AS TEXT);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; END IF;<br>
ELSE<br>
&nbsp;&nbsp;&nbsp;&nbsp; RETURN CAST(field1 AS TEXT)||delimiter||field2;<br>
END IF;<br>
END;<br>
$$ LANGUAGE plpgsql;<br>
<br>
CREATE OR REPLACE<br>
FUNCTION GROUP_CONCAT_ATOM(field1 INT8, field2 INT8, delimiter
TEXT)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RETURNS TEXT AS $$<br>
BEGIN<br>
IF field1 IS NULL THEN<br>
&nbsp;&nbsp; IF field2 IS NULL THEN<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RETURN NULL;<br>
&nbsp;&nbsp; ELSE<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RETURN CAST(field2 AS TEXT);<br>
&nbsp;&nbsp; END IF;<br>
ELSIF field2 IS NULL THEN<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IF field1 IS NULL THEN<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RETURN NULL;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ELSE<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RETURN CAST(field1 AS TEXT);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; END IF;<br>
ELSE<br>
&nbsp;&nbsp;&nbsp;&nbsp; RETURN CAST(field1 AS TEXT)||delimiter||CAST(field2 AS
TEXT);<br>
END IF;<br>
END;<br>
$$ LANGUAGE plpgsql;<br>
<br>
-- permutation of function arguments without delimiter
furnished:<br>
CREATE OR REPLACE<br>
FUNCTION GROUP_CONCAT_ATOM(field1 TEXT, field2 TEXT) --
delimiter=','<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RETURNS TEXT AS $$<br>
BEGIN<br>
IF field1 IS NULL THEN<br>
&nbsp;&nbsp; IF field2 IS NULL THEN<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RETURN NULL;<br>
&nbsp;&nbsp; ELSE<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RETURN CAST(field2 AS TEXT);<br>
&nbsp;&nbsp; END IF;<br>
ELSIF field2 IS NULL THEN<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RETURN field1;<br>
ELSE<br>
&nbsp;&nbsp;&nbsp;&nbsp; RETURN field1||','||field2;<br>
END IF;<br>
END;<br>
$$ LANGUAGE plpgsql;<br>
<br>
CREATE OR REPLACE<br>
FUNCTION GROUP_CONCAT_ATOM(field1 INT8, field2 INT8) --
delimiter=','<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RETURNS TEXT AS $$<br>
BEGIN<br>
IF field1 IS NULL THEN<br>
&nbsp;&nbsp; IF field2 IS NULL THEN<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RETURN NULL;<br>
&nbsp;&nbsp; ELSE<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RETURN CAST(field2 AS TEXT);<br>
&nbsp;&nbsp; END IF;<br>
ELSIF field2 IS NULL THEN<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IF field1 IS NULL THEN<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RETURN NULL;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ELSE<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RETURN CAST(field1 AS TEXT);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; END IF;<br>
ELSE<br>
&nbsp;&nbsp;&nbsp;&nbsp; RETURN CAST(field1 AS TEXT)||','||CAST(field2 AS TEXT);<br>
END IF;<br>
END;<br>
$$ LANGUAGE plpgsql;<br>
<br>
CREATE OR REPLACE<br>
FUNCTION GROUP_CONCAT_ATOM(field1 INT8, field2 TEXT)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RETURNS TEXT AS $$<br>
BEGIN<br>
IF field1 IS NULL THEN<br>
&nbsp;&nbsp; RETURN field2;<br>
ELSIF field2 IS NULL THEN<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IF field1 IS NULL THEN<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RETURN NULL;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ELSE<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RETURN CAST(field1 AS TEXT);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; END IF;<br>
ELSE<br>
&nbsp;&nbsp;&nbsp;&nbsp; RETURN CAST(field1 AS TEXT)||','||field2;<br>
END IF;<br>
END;<br>
$$ LANGUAGE plpgsql;<br>
<br>
CREATE OR REPLACE<br>
FUNCTION GROUP_CONCAT_ATOM(field1 TEXT, field2 INT8) --
delimiter=','<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RETURNS TEXT AS $$<br>
BEGIN<br>
IF field1 IS NULL THEN<br>
&nbsp;&nbsp; IF field2 IS NULL THEN<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RETURN NULL;<br>
&nbsp;&nbsp; ELSE<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RETURN CAST(field2 AS TEXT);<br>
&nbsp;&nbsp; END IF;<br>
ELSIF field2 IS NULL THEN<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RETURN field1;<br>
ELSE<br>
&nbsp;&nbsp;&nbsp;&nbsp; RETURN field1||','||CAST(field2 AS TEXT);<br>
END IF;<br>
END;<br>
$$ LANGUAGE plpgsql;<br>
<br>
-- aggregates for all parameter types with delimiter:<br>
DROP AGGREGATE IF EXISTS GROUP_CONCAT(TEXT, TEXT); -- field,
delimiter<br>
CREATE AGGREGATE GROUP_CONCAT(TEXT, TEXT) -- field, delimiter<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (SFUNC=GROUP_CONCAT_ATOM,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; STYPE=TEXT<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; );<br>
<br>
DROP AGGREGATE IF EXISTS GROUP_CONCAT(INT8, TEXT); -- field,
delimiter<br>
CREATE AGGREGATE GROUP_CONCAT(INT8, TEXT) -- field, delimiter<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (SFUNC=GROUP_CONCAT_ATOM,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; STYPE=TEXT<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; );<br>
<br>
-- aggregates for all parameter types without the optional
delimiter:<br>
DROP AGGREGATE IF EXISTS GROUP_CONCAT(TEXT); -- field,
delimiter=','<br>
CREATE AGGREGATE GROUP_CONCAT(TEXT) -- field<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (SFUNC=GROUP_CONCAT_ATOM,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; STYPE=TEXT<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; );<br>
<br>
DROP AGGREGATE IF EXISTS GROUP_CONCAT(INT8); -- field,
delimiter=','<br>
CREATE AGGREGATE GROUP_CONCAT(INT8) -- field<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (SFUNC=GROUP_CONCAT_ATOM,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; STYPE=TEXT<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; );<br>
</tt></big></big><br>
</body>
</html>

Attachment Content-Type Size
unknown_filename text/html 10.4 KB

Responses

Browse pgsql-general by date

  From Date Subject
Next Message Sergey Konoplev 2013-08-04 05:16:13 Re: Installing 9.2 on Ubuntu from packages: what is the current recommendation?
Previous Message Carlos Henrique Reimer 2013-08-03 18:41:23 Exit code -1073741819