假如有如下表,其中各个i值对应的行数是不定的

  1. SQL> select * from t;
  2. I A          D
  3. ---------- ---------- -------------------
  4. 1 b          2008-03-27 10:55:42
  5. 1 a          2008-03-27 10:55:46
  6. 1 d          2008-03-27 10:55:30
  7. 2 z          2008-03-27 10:55:55
  8. 2 t          2008-03-27 10:55:59
  9. --- 要获得如下结果,注意字符串需要按照D列的时间排序:
  10. 1  d,b,a
  11. 2  z,t

这是一个比较典型的行列转换,有好几种实现方法

1.自定义函数实现

  1. create or replace function my_concat(n number)
  2. return varchar2
  3. is
  4. type typ_cursor is ref cursor;
  5. v_cursor typ_cursor;
  6. v_temp varchar2(10);
  7. v_result varchar2(4000):= '';
  8. v_sql varchar2(200);
  9. begin
  10. v_sql := 'select a from t where i=' || n ||' order by d';
  11. open v_cursor for v_sql;
  12. loop
  13. fetch v_cursor into v_temp;
  14. exit when v_cursor%notfound;
  15. v_result := v_result ||',' || v_temp;
  16. end loop;
  17. return substr(v_result,2);
  18. end;
  19. SQL> select i,my_concat(i) from t group by i;
  20. I MY_CONCAT(I)
  21. ---------- --------------------
  22. 1 d,b,a
  23. 2 z,t

虽然这种方式可以实现需求,但是如果表t的数据量很大,i的值又很多的情况下,因为针对每个i值都要执行一句select,扫描和排序的次数和i的值成正比,性能会非常差。

2.使用sys_connect_by_path

  1. select i,ltrim(max(sys_connect_by_path(a,',')),',') a
  2. from
  3. (
  4. select i,a,d,min(d) over(partition by i) d_min,
  5. (row_number() over(order by i,d))+(dense_rank() over (order by i)) numid
  6. from t
  7. )
  8. start with d=d_min connect by numid-1=prior numid
  9. group by i;

从执行计划上来看,这种方式只需要扫描两次表,比自定义函数的方法,效率要高很多,尤其是表中数据量较大的时候: 
 
3.使用wm_sys.wm_concat 
这个函数也可以实现类似的行列转换需求,但是似乎没有办法做到直接根据另外一列排序,所以需要先通过子查询或者临时表排好序:

  1. SQL> select i,wmsys.wm_concat(a) from t group by i;
  2. I WMSYS.WM_CONCAT(A)
  3. ---------- --------------------
  4. 1 b,a,d
  5. 2 z,t
  6. SQL> select i,wmsys.wm_concat(a)
  7. 2  from
  8. 3  (select * from t order by i,d)
  9. 4  group by i;
  10. I WMSYS.WM_CONCAT(A)
  11. ---------- --------------------
  12. 1 d,b,a
  13. 2 z,t

执行计划上看,只需要做一次表扫描就可以了,但是这个函数是加密过的,执行计划并不能显示函数内部的操作。

Oracle 多行合并一行 方法的更多相关文章

  1. oracle多行合并一行

    以上图为例 执行SQL语句: select d.group_id,to_char(wm_concat(d.tag)) from Imglib_Group_Tag d where d.group_id= ...

  2. SQL实现多行合并一行 .

    ORACLE纯SQL实现多行合并一行[转] 项目中遇到一个需求,需要将多行合并为一行.表结构如下:NAME                            Null           Type ...

  3. ORACLE纯SQL实现多行合并一行

    项目中遇到一个需求,需要将多行合并为一行.表结构如下:NAME                            Null           Type---------------------- ...

  4. JS行合并处理方法

    //行合并 function _w_table_rowspan(col){ _w_table_firsttd = ""; _w_table_currenttd = "&q ...

  5. oracle 多行合并为一行

    sys_connect_by_path select i,ltrim(max(sys_connect_by_path(a,',')),',') afrom(select i,a,d,min(d) ov ...

  6. Sql:多行合并一行以及多条数据取时间最早的那条

    有两个导数据的需求,1.一张表里面每一个订单号可能对应多条数据,每个单号返回时间最早的那条. 2.根据条件查询某个字段并按照逗号,合并在一起. 表类似结构如下: 第一条sql:select c.Id, ...

  7. oracle 多行变一行 wmsys.wm_concat

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

  8. Oracle PIVOT 行转列方法

    数据库中業種的存储如下图: SELECT * FROM M_TORIHIKISAKI_GYOSYU 其中GYIUSYU_CD字段代表不同的業種 而画面需要实现下图所示样式:(将每条数据的業種横向展开显 ...

  9. Oracle 多行变一行

    https://blog.csdn.net/rainyspring4540/article/details/50231521

随机推荐

  1. 用Omniauth来Login with Facebook(Go-rails课程)

    https://gorails.com/episodes/login-with-facebook?autoplay=1 大概看了一遍,留了视频的截图. https://gorails.com/epis ...

  2. Confluence 6 安装 Active Directory 证书服务器

    如果证书服务器已经安装了的话,跳过这一步骤,直接进入下一步.下面步骤中的屏幕截图是从 Windows 2008 服务器版上安装的截图,针对 2000 和 2003 安装过程是一样的. 作为系统管理员登 ...

  3. ccf交通规划

    一.试题 问题描述  G国国王来中国参观后,被中国的高速铁路深深的震撼,决定为自己的国家也建设一个高速铁路系统.  建设高速铁路投入非常大,为了节约建设成本,G国国王决定不新建铁路,而是将已有的铁路改 ...

  4. hdu-2227-dp+bit

    Find the nondecreasing subsequences Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/3 ...

  5. nyoj 1238(BFSor最短路)

    最少换乘 时间限制:2000 ms  |  内存限制:65535 KB 难度:3   描述 欧洲某城是一个著名的旅游胜地,每年都有成千上万的人前来观光旅行.Dr. Kong决定利用暑假好好游览一番.. ...

  6. Leetcode 94

    /** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode ...

  7. mysql 查询某一主键在那些表中中被设置为外键了

    use information_schema; show tables; select * from KEY_COLUMN_USAGE where COLUMN_NAME='areaid';

  8. 在linux中,如何增加、修改、删除、暂停和冻结用户名

    在Linux中,如何增加.修改.删除.暂停和冻结用户名 在操作增加.修改和删除用户名前,先认识linux中两个最重要的文件,它们就是账号管理最重要文件“/etc/passwd”与“etc/shadow ...

  9. oracle增加表空间

    select tablespace_name, sum(bytes)/1024/1024 from dba_data_files group by tablespace_name; select ta ...

  10. learning scala read from console

    控制台输入语句: readInt, readDouble, readByte, readShort, readLong, readChar, readBoolean, readLine example ...