不得了!这个国产数据库居然实现了Oracle的聚合函数wm_concat
熟悉 Oracle 的朋友一定听说过或使用过这个聚合函数vm_concat。说到这个函数,含泪的讲,给我们带来了很多故障,当然都是因客户开发商的人员不了解 Oracle 版本变化带来的问题。

是的,实际上 Oracle 11g 之后就不再推荐使用这个函数了,因为它在处理varchar2的时候会导致temp使用暴涨。
然而,很多应用程序在12c或19c中可能自定义了类似wm_concat的函数,例如 my_wm_concat。这些函数被广泛使用在应用程序中,当这些应用程序的数据库迁移到国产数据库如 MogDB 时,如果希望数据库层面兼容而不修改应用代码,我们就需要实现函数兼容。
在开源 PostgreSQL 版本中有string_agg函数实现类型功能,MogDB 中除了支持string_agg之外,同时还支持listagg(是的,你没有看错,还兼容 Oracle 12c的listagg函数),也自带了wm_concat。但需要注意的是,MogDB 中vm_concat函数不支持像 Oracle 一样的synonym给个别名,需要创建函数。
这里给大家简单分享一下:
MogDB=# \da+ wm_concat<br> List of aggregate functions<br> Schema | Name | Result data type | Argument data types | Description<br>------------+-----------+------------------+---------------------+-------------<br> pg_catalog | wm_concat | text | text |<br>(1 row)<br><br>SELECT p.proname AS function_name,<br> pg_catalog.pg_get_function_result(p.oid) AS result_type,<br> pg_catalog.pg_get_function_arguments(p.oid) AS argument_types,<br> CASE<br> WHEN p.proisagg THEN 'agg'<br> ELSE 'normal'<br> END AS function_type<br> ,a.aggtransfn,a.aggfinalfn<br> FROM pg_catalog.pg_proc p<br>LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace<br>LEFT JOIN pg_catalog.pg_aggregate a ON a.aggfnoid = p.oid<br> WHERE a.aggfnoid IS NOT NULL<br> AND p.proname like 'wm_concat%';<br> <br> function_name | result_type | argument_types | function_type | aggtransfn | aggfinalfn<br>---------------+-------------+----------------+---------------+----------------------+----------------------<br> wm_concat | text | text | agg | vm_concat_state_func | vm_concat_final_func<br><br>SELECT p.proname AS function_name,<br> pg_catalog.pg_get_function_result(p.oid) AS result_type,<br> pg_catalog.pg_get_function_arguments(p.oid) AS argument_types,<br> CASE<br> WHEN p.proisagg THEN 'agg'<br> ELSE 'normal'<br> END AS function_type<br> ,a.aggtransfn,a.aggfinalfn<br> FROM pg_catalog.pg_proc p<br>LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace<br>LEFT JOIN pg_catalog.pg_aggregate a ON a.aggfnoid = p.oid<br> WHERE a.aggfnoid IS NOT NULL<br> AND p.proname like 'string_agg%';<br> <br> function_name | result_type | argument_types | function_type | aggtransfn | aggfinalfn<br>---------------+-------------+----------------+---------------+--------------------------+--------------------------<br> string_agg | text | text, text | agg | string_agg_transfn | string_agg_finalfn<br> string_agg | bytea | bytea, bytea | agg | bytea_string_agg_transfn | bytea_string_agg_finalfn<br>(2 rows)<br><br>SELECT p.proname AS function_name,<br> pg_catalog.pg_get_function_result(p.oid) AS result_type,<br> pg_catalog.pg_get_function_arguments(p.oid) AS argument_types,<br> CASE<br> WHEN p.proisagg THEN 'agg'<br> ELSE 'normal'<br> END AS function_type<br> ,a.aggtransfn,a.aggfinalfn<br> FROM pg_catalog.pg_proc p<br>LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace<br>LEFT JOIN pg_catalog.pg_aggregate a ON a.aggfnoid = p.oid<br> WHERE a.aggfnoid IS NOT NULL<br> AND p.proname like 'listagg%';<br> <br> function_name | result_type | argument_types | function_type | aggtransfn | aggfinalfn<br>---------------+-------------+-----------------------------------+---------------+-------------------------------------+------------------<br> listagg | text | text, text | agg | list_agg_transfn | list_agg_finalfn<br> listagg | text | text | agg | list_agg_noarg2_transfn | list_agg_finalfn<br> listagg | text | smallint, text | agg | int2_list_agg_transfn | list_agg_finalfn<br> listagg | text | smallint | agg | int2_list_agg_noarg2_transfn | list_agg_finalfn<br> listagg | text | integer, text | agg | int4_list_agg_transfn | list_agg_finalfn<br> listagg | text | integer | agg | int4_list_agg_noarg2_transfn | list_agg_finalfn<br> listagg | text | bigint, text | agg | int8_list_agg_transfn | list_agg_finalfn<br> listagg | text | bigint | agg | int8_list_agg_noarg2_transfn | list_agg_finalfn<br> listagg | text | real, text | agg | float4_list_agg_transfn | list_agg_finalfn<br> listagg | text | real | agg | float4_list_agg_noarg2_transfn | list_agg_finalfn<br> listagg | text | double precision, text | agg | float8_list_agg_transfn | list_agg_finalfn<br> listagg | text | double precision | agg | float8_list_agg_noarg2_transfn | list_agg_finalfn<br> listagg | text | numeric, text | agg | numeric_list_agg_transfn | list_agg_finalfn<br> listagg | text | numeric | agg | numeric_list_agg_noarg2_transfn | list_agg_finalfn<br> listagg | text | date, text | agg | date_list_agg_transfn | list_agg_finalfn<br> listagg | text | date | agg | date_list_agg_noarg2_transfn | list_agg_finalfn<br> listagg | text | timestamp without time zone, text | agg | timestamp_list_agg_transfn | list_agg_finalfn<br> listagg | text | timestamp without time zone | agg | timestamp_list_agg_noarg2_transfn | list_agg_finalfn<br> listagg | text | timestamp with time zone, text | agg | timestamptz_list_agg_transfn | list_agg_finalfn<br> listagg | text | timestamp with time zone | agg | timestamptz_list_agg_noarg2_transfn | list_agg_finalfn<br> listagg | text | interval, text | agg | interval_list_agg_transfn | list_agg_finalfn<br> listagg | text | interval | agg | interval_list_agg_noarg2_transfn | list_agg_finalfn<br>(22 rows)<br><br><br>MogDB=# \df string_agg<br> List of functions<br> Schema | Name | Result data type | Argument data types | Type | fencedmode | propackage | prokind<br>------------+------------+------------------+---------------------+------+------------+------------+---------<br> pg_catalog | string_agg | bytea | bytea, bytea | agg | f | f | f<br> pg_catalog | string_agg | text | text, text | agg | f | f | f<br>(2 rows)<br><br>MogDB=# select wm_concat(name) from test2;<br> wm_concat<br>-----------<br> 1,2,3<br>(1 row)<br><br>MogDB=# select string_agg(name,',') from test2;<br> string_agg<br>------------<br> 1,2,3<br>(1 row)<br><br>MogDB=# select string_agg(name,',' order by id desc ) from test2;<br>select string_agg(name,',' order by id desc ) from test2;<br> string_agg<br>------------<br> 3,2,1<br>(1 row)<br><br>MogDB=# select listagg(name,',') within group(order by id desc ) from test2;<br>select listagg(name,',') within group(order by id desc ) from test2;<br> listagg<br>---------<br> 3,2,1<br>(1 row)<br><br>