Reputation: 1498
I am having the following - simplified - layout for tables:
content.blockId
is a foreign key to blocks.id
. The idea is that in the content table you have many content entries with different types for one block.
I am now looking for a query that can provide me with an aggregation based on a blockId where all the content entries of the 3 different types are concatenated and put into respective columns.
I have already started and found the listagg
function which is working well, I did the following statement and lists me all the content entries in a column:
SELECT listagg(c.data, ',') WITHIN GROUP (ORDER BY c.order) FROM content c WHERE c.blockId = 330;
Now the concatenated string however contains all the data
elements of the block in one column. What I would like to achieve is that its put into separate columns based on the type. For example the following content of content
would be like this:
Now I wanted to get as an output 2 columns, one is FRAGMENT and one is BULK, where FRAGMENT contains "content1;content3;content4" and BULK contains "content2"
Is there an efficient way of achieving this?
Upvotes: 4
Views: 13888
Reputation: 7347
As an alternative, if you want it more dynamic, you could pivot the outcome. Note, that this will only work for Oracle 11.R2. Here´s an example how it could look like:
select * from
(with dataSet as (select 1 idV, 1 bulkid, 0 orderV, 'content1' dataV, 'FRAGMENT' typeV from dual union
select 2, 1, 1, 'content2', 'BULK' from dual union
select 3, 1, 3, 'content4', 'FRAGMENT' from dual union
select 4, 1, 2, 'content3', 'FRAGMENT' from dual)
select typeV, listagg(dataSet.dataV ,',') WITHIN GROUP (ORDER BY orderV) OVER (PARTITION BY typeV) dataV from dataSet)
pivot
(
max(dataV)
for typeV in ('BULK', 'FRAGMENT')
)
O/P
Bulk | FRAGMENT
-----------------
content2 | content1,content3,content4
The important things here:
OVER (PARTITION BY typeV)
: this acts like a group by for the listagg, concatinating everything having the same typeV
.
for typeV in ('BULK', 'FRAGMENT')
: this will gather the data for BULK
and FRAGMENT
and produce separate columns for each.
max(dataV)
simply to provide a aggregate function, otherwise pivot wont work.
Upvotes: 2
Reputation: 1269633
You can use case
:
SELECT listagg(CASE WHEN content = 'FRAGMENT' THEN c.data END, ',') WITHIN GROUP (ORDER BY c.order) as fragments,
listagg(CASE WHEN content = 'BULK' THEN c.data END, ',') WITHIN GROUP (ORDER BY c.order) as bulks
FROM content c
WHERE c.blockId = 330;
Upvotes: 7