I need something similar to these 2 SO questions, but using Informix SQL syntax.
My data coming in looks like this:
id codes
63592 PELL
58640 SUBL
58640 USBL
73571 PELL
73571 USBL
73571 SUBL
I want to see it come back like this:
id codes
63592 PELL
58640 SUBL, USBL
73571 PELL, USBL, SUBL
See also group_concat() in Informix.
Building on Jonathan Leffler example and on RET comments about the ordering of the concatenated values, using Informix 12.10FC8DE, I came up with the following user aggregate:
The concatenated values will have no duplicates and will be ordered.
I used Informix
collections
, namelySET
that does not allow duplicate values, to try to keep the code somewhat simple.The method is to use
SET
's to keep the intermediate results (and eliminating the duplicates) and at the end build the concatenated string from the ordered values of the finalSET
.The use of
LVARCHAR
for theSET
elements is due to the fact that initially i was usingVARCHAR
but the memory consumption was very, very high. The documentation hints that internally Informix may be casting theVARCHAR
toCHAR
. I made the change and it did in fact lower the memory consumption (but it is still high).However, this aggregate memory consumption is around 2 orders of magnitude higher than Jonathan's and about 2 times slower on the tests i conducted (using a table with around 300 000 rows).
So use with care. It consumes a lot of memory and it is not extensively tested ( it may be leaking memory somewhere ).
EDIT 1:
My previous code must be leaking a memory structure somewhere (or internally Informix keeps the collection derived tables around, and it can generated a lot of those).
So, still trying to avoid having to code the aggregate function in
C
, here is another alternative, using InformixBSON
built in functions, that will use much less memory and be a bit faster.The aggregated return value will be ordered and without duplicates.
Again, this was not properly tested. It is a just a POC.
One of the problems is that it is not sanitizing the input values. Some of the
BSON
manipulating functions receive parameters that are being built by concatenating strings and non escaped characters can break those parameters. For example, a string value with quotes on it:'I"BrokeIt'
) can provoke an assortment of errors (Assert Failures included).And i am certain there are other problems.
However, memory consumption of this implementation is in the same order of magnitude as in Jonathan's example and around 60% slower (again, only very rudimentary testing was performed).
Also, if informix allows you to create user-functions, you could create a function that returned a string with the concatenated value.
I believe that the answer you need is a user-defined aggregate, similar to this one:
Given a table of elements (called elements) with a column called name containing (funnily enough) the element name, and another column called atomic_number, this query produces this result:
Applied to the question, you should obtain the answer you need from:
The output from that is:
The extra set of data was added to test whether insert sequence affected the result; it appears not to do so (the codes are in sorted order; I'm not sure whether there's a way to alter - reverse - that order).
Notes:
LVARCHAR(10240)
(for 10 KiB), for example.SQL -528: Maximum output rowsize (32767) exceeded
, which surprises me.If you need to remove the aggregate, you can use:
I'm not sure about informix sql, but in MSSQL or Oracle, you could do this with the
DECODE or CASE keywords, by concatenating them together. However, this would require you to know all the potential values ahead of time, which is brittle.
I'm assuming the reason you don't like the STUFF keyword is because informix does not support it?
Oracle also supports the CONNECT BY keywords, which would work, but again may not be supported by informix.
Probably the best answer would be to build this output in your client/data layer, after the query. Is there a particular reason why this must be done in the query?
I'd like to point you this answer on another similar question on Stack Overflow. You're looking for something like MySQL's
group_concat()
function.