简体   繁体   English

Oracle SQL有条件将行聚合到列listagg中

[英]Oracle SQL aggregate rows into column listagg with condition

I am having the following - simplified - layout for tables: 我有以下-简化-表格布局:

  • TABLE blocks (id) TABLE块(ID)
  • TABLE content (id, blockId, order, data, type) 表格内容(id,blockId,顺序,数据,类型)

content.blockId is a foreign key to blocks.id . content.blockIdblocks.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. 我现在正在寻找一个查询,该查询可以为我提供基于blockId的聚合,其中将3种不同类型的所有内容条目连接在一起并放入相应的列中。

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: 我已经启动并找到运行良好的listagg函数,我做了以下声明,并在列中列出了所有内容条目:

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. 现在,连接字符串现在在一列中包含了该块的所有data元素。 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: 例如以下内容content是这样的:

  • 1, 1, 0, "content1", "FRAGMENT" 1,1,0,“ content1”,“ FRAGMENT”
  • 2, 1, 1, "content2", "BULK" 2、1、1,“ content2”,“ BULK”
  • 3, 1, 3, "content4", "FRAGMENT" 3、1、3,“ content4”,“ FRAGMENT”
  • 4, 1, 2, "content3", "FRAGMENT" 4、1、2,“ content3”,“ FRAGMENT”

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" 现在我想获得2列作为输出,一列是FRAGMENT,一列是BULK,其中FRAGMENT包含“ content1; content3; content4”,而BULK包含“ content2”

Is there an efficient way of achieving this? 是否有一种有效的方法来实现这一目标?

You can use case : 您可以使用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;

As an alternative, if you want it more dynamic, you could pivot the outcome. 或者,如果您希望它更具动态性,则可以调整结果。 Note, that this will only work for Oracle 11.R2. 请注意,这仅适用于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 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 . OVER (PARTITION BY typeV) :这类似于OVER (PARTITION BY typeV)的group by,将具有相同typeV所有内容typeV

for typeV in ('BULK', 'FRAGMENT') : this will gather the data for BULK and FRAGMENT and produce separate columns for each. for typeV in ('BULK', 'FRAGMENT') :这将收集BULKFRAGMENT的数据,并为每个生成单独的列。

max(dataV) simply to provide a aggregate function, otherwise pivot wont work. max(dataV)仅提供聚合功能,否则数据透视将无法工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM