Oracle 11g行字段拼接WMSYS.WM_CONCAT问题Not A LOB

一、问题出现

项目中的某个查询需要将表中某个字段不重复地拼接起来,百度得到该函数WMSYS.WM_CONCAT(字段),以及listagg(字段,连接符)函数,前者只能使用逗号','连接,后者可以定制连接符。

但由于listagg不能直接在参数中使用distinct去重,因此采用WM_CONCAT函数。

SQL格式如下:

select t.id, t.pjname
from (select A.id as id, count(distinct B.name) as countname,
to_char(wmsys.wm_concat(distinct to_char(B.name))) as pjname
from A left join B on A.id = B.id
where 1 = 1
group by A.id) t
where t.countname > 1;

这段SQL的作用是,以A表的id为组,不重复的拼接B表的name,并统计name去重后的个数,最后返回name去重后仍多于1个的id和拼接name。

开发时这段SQL是正常的,然而,这段SQL在测试库上却会报错ORA-22922: 不存在的 LOB 值

二、原因分析

经网上查资料,发现问题出在WMSYS.WM_CONCAT函数在Oracle不同版本中的返回值类型不同。

该项目开发使用的是Oracle 11.2.0.1.0,而测试与现场使用的均为Oracle 11.2.0.4.0,项目开始时的疏忽导致开发与测试的不一致。

将拼接函数外的to_char去掉后,SQL不会报错,但对象不是String类型(可能是java.sql.Clob类型),无法直接toString获得。

同时,在PLSQL Developer 9.0中直接运行SQL时,该拼接结果直接显示为<CLOB>,可在select结果中使用to_char()函数,而该函数在项目dal层直接运行仍报错。

三、问题解决

  1. 去掉WM_CONCAT函数外的to_char()
select t.id, t.pjname
from (select A.id as id, count(distinct B.name) as countname,
wmsys.wm_concat(distinct to_char(B.name)) as pjname
from A left join B on A.id = B.id
where 1 = 1
group by A.id) t
where t.countname > 1;
  1. 将LOB类型对象转换为String类型,有两种方法:在SQL中使用Oracle函数,或者在后端dal层转换,参考网上的文章,我选择后者,因为完整的SQL要实现的功能本身比较复杂,要尽量简化在数据库中的操作。
  • 获取结果集中的字段并判断
    String array1 = "";
try {
array = array[1].getClass().toString().equals("class java.lang.String") ? array[1].toString() : ClobToString((Clob) array[1]);
} catch (SQLException e) {
array14 = array[1].toString();
} catch (IOException e) {
e.printStackTrace();
}
	public String ClobToString(Clob clob) throws SQLException, IOException {
String reString = "";
Reader is = clob.getCharacterStream();
BufferedReader br = new BufferedReader(is);
String s = br.readLine();
StringBuffer sb = new StringBuffer();
while (s != null) {
sb.append(s);
s = br.readLine();
}
reString = sb.toString();
if(br!=null){
br.close();
}
if(is!=null){
is.close();
}
return reString;
}

问题解决。还是得看看listagg方法的用法,毕竟官方兼容性强些,但觉得listagg不如WM_CONCAT简单易用。

三、补充

listagg(列名,'分隔符')除了要多嵌套一层子查询,其实也挺方便的,它是从11g起才出现的聚合函数,要实现去重和统计,需要使用distinct的多列去重。

select A.id, t.countname, t.pjname
from A
left join (SELECT id,count(name) as countname,
LISTAGG(to_char(name), ',') WITHIN GROUP(ORDER BY name) AS pjname
FROM (select distinct B.id as id, B.name as name
from B
left join C
on B.name = C.name
where C.gender = 'female')
where 1 = 1
group by id) t
on A.id = t.id
where countname is null or countname <= 1;

四、参考文章

Oracle 11g行字段拼接WMSYS.WM_CONCAT问题Not A LOB的更多相关文章

  1. oracle 多行变一行 wmsys.wm_concat

    背景        还是那个问题,部分程序员喜欢用sql解决问题.发现了这个函数,当初真是大喜过望,现在是哭笑不得.10g支持这个函数,11好像不支持了,而且只有oracle支持,其实自己写个通用方法 ...

  2. Oracle 行拼接 wmsys.wm_concat扩展

    将多行数据拼接成一行: --wmsys.wm_concat group by a.flowid; 但有大小限制:字符串缓冲区太小,超过varchar 4000长度.扩展:更改返回类型为clob --T ...

  3. Oracle数据库合并行记录,WMSYS.WM_CONCAT 函數的用法

    Sql代码 select t.rank, t.Name from t_menu_item t; 10 CLARK    10 KING    10 MILLER    20 ADAMS    20 F ...

  4. oracle 11g行转列 列转行

    行转列: SELECT *   FROM   src_table   UNPIVOT (param_value FOR param_name IN (product_color AS 'product ...

  5. mysql 多个字段拼接

    Mysql的查询结果行字段拼接,能够用以下两个函数实现: 1. concat函数 mysql> select concat('1','2','3') from test ; +--------- ...

  6. mysql函数之四:concat() mysql 多个字段拼接

    语法: COUNT(DISTINCT expr ,[expr ...]) 函数使用说明:返回不同的非NULL 值数目.若找不到匹配的项,则COUNT(DISTINCT) 返回 0 Mysql的查询结果 ...

  7. mysql多个字段拼接

    Mysql的查询结果行字段拼接,可以用下面两个函数实现: 1. concat函数 mysql') from test ; +---------------------+ ') | +--------- ...

  8. Oracle中将列查询结果多行逗号拼接成一个大字段

    在11G以下版本中oracle有自带的函数wm_concat可以实现,如: select wm_concat(id) from table where col='1' 但是在12C版本中此函数无法使用 ...

  9. Oracle之多行记录变一行记录,行变列,并排序(wmsys.wm_concat)

    原帖:http://www.cnblogs.com/nayitian/p/3231734.html wmsys.wm_concat Definition: The Oracle PL/SQL WM_C ...

随机推荐

  1. 如何优雅地进行错误处理(clean code阅读笔记之六)

    错误处理是十分必要的,但是如果对错误处理使用不当则会让代码变得十分臃肿,让阅读者看不清代码的逻辑,更严重的是,这也会让程序变得十分脆弱.本文中将列出一些使用错误处理的技巧,帮助你写出既简洁又健壮的代码 ...

  2. Android活动的启动模式

    1. standard 标准模式,是活动默认的启动模式,在不进行显示指定的情况下,所有活动都会自动使用这种模式. Android使用返回栈管理活动,在standard模式下,每当启动一个新的活动,它就 ...

  3. ADO.NET教程(1)初识ado.net

    ADO.NET简介 ADO.NET使用到的类 需掌握的方法和属性 ado.net连接实例 ADO.NET的名称起源于ADO(ActiveX Data Objects),是一个COM组件库,用于在以往的 ...

  4. Scala 知识点掌握2

    Scala 基础知识点巩固2 1.集合中常用的函数 sum / max / min # 定义一个List[Int]val list1 = List(1,3,4,6,8,9)# 取集合中所有元素的和li ...

  5. HDU 5007 字符串匹配

    http://acm.hust.edu.cn/vjudge/contest/122814#problem/A 匹配到字符串就输出,水题,主要是substr的运用 #include <iostre ...

  6. PAT 1037 Magic Coupon

    #include <cstdio> #include <cstdlib> #include <vector> #include <algorithm> ...

  7. mysql三:表操作

    一.存储引擎介绍 存储引擎即表类型,mysql根据不同的表类型会有不同的处理机制. 详见:点击查看 二.表的介绍 表相当于文件,表中的一条记录就相当于文件的一行内容,不同的是,表中的一条记录有对应的标 ...

  8. Linux漏洞分析入门笔记-Off-By-One(栈)

    ubuntu-16.04.5(X86) IDA7.0 0x00.漏洞描述 1.什么是off by one?又称1字节溢出. 源字符串长度等于目标缓冲区长度时,将源字符串复制到目标缓冲区可能会导致off ...

  9. Android 从 Web 唤起 APP

    前言 知乎在手机浏览器打开,会有个 App 内打开的按钮,点击直接打开且跳转到该详情页,是不是有点神奇,是如何做到的呢? 效果预览 Uri Scheme 配置 intent-filter Androi ...

  10. office转换为html在线预览

    /// <summary> /// word 转换为html /// </summary> /// <param name="path">要转换 ...