在Oracle语法中从Postgres编写数组函数

时间:2015-08-03 17:12:26

标签: oracle postgresql

在Postgres中,我会这样做:

SELECT main.*
    , array(SELECT columnA FROM tableB alt WHERE alt.columnB = main.columnB) AS columnAs_to_tableA
FROM tableA main

Oracle 10中如何做同样的事情?应该注意的是我不能使用listagg。我找到了类似问题的答案:Aggregate String Concatenation in Oracle 10g 我不知道这个答案是如何起作用的,也不知道这是否是“正确的”解决方案,因为它从未被标记为已接听/接受。

我想用一个例子回答这个问题,使用我提供的一对一比较的表名,对于寻求相同答案的其他人来说可能效果最好。

谢谢

编辑1:我应该补充一点,我想避免引入新的架构元素,如表格,函数等......

编辑2:删除阵列的要求。逗号分隔的字符串就足够了。

1 个答案:

答案 0 :(得分:2)

如果要返回集合,则需要创建一个类型并使用collect填充该类型。

CREATE TYPE typ_columnA_nt
    AS TABLE OF <<columnA data type>>

然后您可以使用collect功能

SELECT main.*
    , cast( collect(SELECT columnA 
                      FROM tableB alt 
                    WHERE alt.columnB = main.columnB)
            as typ_columnA_nt ) AS columnAs_to_tableA
FROM tableA main

如果要返回光标,可以使用cursor功能

SELECT main.*,
       cursor( SELECT columnA
                 FROM tableB alt
                WHERE alt.columnB = main.columnB ) as columnAs_to_tableA
  FROM tableA main

如果要返回以逗号分隔的字符串,Tim Hall有一个string aggregation techniques in Oracle的规范列表。在listagg不可选的版本中,我的偏好是创建user-defined aggregate function,这样您就可以

select main.*,
       (select string_agg(columnA)
          from tableB alt
         where alt.columnB = main.columnB) as columnAs_to_tableA
  from tableA main 

如果您仅限于不涉及创建新对象的解决方案,最简单的选择是使用wm_concat,尽管这不受官方支持

select main.*,
       (select wm_concat(columnA)
          from tableB alt
         where alt.columnB = main.columnB) as columnAs_to_tableA
  from tableA main 

如果你不能创建任何支持对象,并且你不能使用不支持的函数,那么你就会陷入旧的row_number and sys_connect_by_path option,这有点难看。我想你会想要这样的东西,但我有一个很小的机会,我犯了一个小的语法错误。

select main.*,
       agg.value_string
  from tableA main
       left join (select alt_outer.columnB,
                         ltrim(max(sys_connect_by_path(alt_outer.columnA,','))
                                  keep( dense_rank last order by alt_outer.columnA ),
                               ',') as value_string
                    from (select alt.columnA,
                                 alt.columnB,
                                 row_number() over (partition by alt.columnB
                                                        order by alt.columA) as curr,  
                                 row_number() over (partition by alt.columnB
                                                        order by alt.columA) -1 as prev
                            from tableB alt) alt_outer
                    group by alt_outer.columnB
                  connect by alt_outer.prev = prior alt_outer.curr
                         and alt_outer.columnB = prior alt_outer.columnB
                    start with alt_outer.curr = 1) agg
         on( main.columnB = agg.columnB )

另一种选择是使用XML函数

SELECT main.* , 
       tableB_alt.list AS columnAs_to_tableA 
  FROM tableA main 
       LEFT JOIN ( SELECT columnB ,
                          TRIM(TRAILING ',' 
                                 FROM 
                                 XMLAGG(
                                   XMLELEMENT(E,columnA||',')
                                 ).EXTRACT('//text()')
                              ) list 
                     FROM tableB 
                    GROUP BY columnB ) tableB_alt 
         ON tableB_alt.columnB = main.columnB