zoukankan      html  css  js  c++  java
  • 使用SQL如何把用逗号等字符隔开的字符串转换成列表,以及把列合并成符合隔开的字符串(转)

    如何把用逗号等字符隔开的字符串转换成列表,下面依逗号分隔符为例:

    比如有一个字符串,其值为:香港,张家港,北京,上海
    用SQL把这个字符串转换成列表的方法是:

    1、方法一

    WITH A AS (SELECT '香港,张家港,北京,上海' A FROM DUAL)
    SELECT DECODE(B,0,SUBSTR(A,C),SUBSTR(A,C,B-C)) city  FROM
    (
    SELECT A,B,(LAG(B,1,0) OVER(ORDER BY LV))+1 C
    FROM(
    SELECT A,INSTR(A,',',1,LEVEL) B,LEVEL LV FROM A
    CONNECT BY LEVEL <=(LENGTH(A) - LENGTH(REPLACE(A,',','')))+1
    )
    )

    输出结果是:

    香港
    张家港
    北京
    上海

    应用举例:
    如果table1表的city字段的值为:北京;table2表的city字段的值为:香港,张家港,北京,上海
    要想用city字段关联table1,table2表来查询table1表中的数据,首先我们会想到用(例:select * from table1 where field in (select field from table2))方式来查询,但是这样查询的结果却不正确,仔细观察会发现如果用in时,table2表的city字段的值必须得是('香港','张家港','北京','上海')格式,这样查询的结果才会正确,这时如果我们使用下面的SQL就可帮我们解决这个问题了。

    例:select * from table where field in ( 
    WITH A AS (SELECT (select field from table2) A FROM DUAL)
    SELECT DECODE(B,0,SUBSTR(A,C),SUBSTR(A,C,B-C)) city  FROM
    (SELECT A,B,(LAG(B,1,0) OVER(ORDER BY LV))+1 C
    FROM(SELECT A,INSTR(A,',',1,LEVEL) B,LEVEL LV FROM A
    CONNECT BY LEVEL <=(LENGTH(A) - LENGTH(REPLACE(A,',','')))+1
    )))

    2、方法二:使用Oracle regexp_substr中的正则表达式

    WITH temp AS
         (SELECT '香港,张家港,北京,上海,95,aa' text
            FROM DUAL)
    SELECT regexp_substr (text, '[^,]+', 1, rn) city
      FROM temp t1,
           (SELECT     LEVEL rn
                  FROM DUAL
            CONNECT BY LEVEL <=
                          (SELECT   LENGTH (text)
                                  - LENGTH (REPLACE (text, ',', ''))
                                  + 1
                             FROM temp)) t2

    3、方法三:使用的表(FW_ANSWER)

    select answer from fw_answer
       
       ANSWER
       -----------------
       A,B,C
       A,F
       B,D,E
       D

      要把逗号分隔的转列换成行显示,这里使用了substr的方式,如下:

     select substr(answer,instr(','||answer|| ',', ',', 1, t2.row_num),
                     instr(','||answer|| ',', ',', 1, t2.row_num+1)-1-instr(','||answer, ',', 1, t2.row_num)) answer
       from fw_answer t1,(select rownum row_num from user_objects where rownum<= 10) t2
       where nvl(substr(answer,instr(','||answer||',', ',', 1, t2.row_num),
                     instr(','||answer||',', ',', 1, t2.row_num+1)-1-instr(','||answer, ',', 1, t2.row_num)),'-')!='-'
       order by answer

       查询结果:

      ANSWER
        -----------------
        A
        A
        B
        B
        C
        D
        D
        E
        F   

      【如果是使用其他字符分隔的,以上方式也可以,只需要将有逗号的地方换成该字符。】 
       以上方式是针对字符存储无规律的情况,对于fw_answer表中的答案列是有规律可循的,所以简化后的sql如下:

      select substr(answer,t2.row_num*2-1,1) answer
       from fw_answer t1,(select rownum row_num from user_objects where rownum<= 10) t2
       where nvl(substr(answer,t2.row_num*2-1,1),'-')!='-'
       order by answer 

      【注:user_objects主要描述当前用户通过DDL建立的所有对象。包括表、视图、索引、存储过程、触发器、
       包、索引、序列等。是oracle字典表的视图。这里也可以通过其它方式,如dual,此处为了免去content by
       所以不用dual,用user_objects。】 

    ------------------------------------------------------------------------------------------------------

    正好相反的操作:把列转换成行
    从网上找了都是关于decode的方法实现的列转行,后来发现了用orcale的wmsys.wm_concat方法可以轻松的实现,下面的范例是网上找的:wmsys.wm_concat要10g以后才可以。

        表结构: 
         1  A
         1  B
         1  C
         2  A
         2  B
         3  C
         3  F
         4  D
         转换后变成:      
         1  A,B,C
         2  A,B
         3  C,F
         4  D

      方法:

    假设你的表结构是tb_name(id, remark),则语句如下:
    SELECT a.id, wm_concat (a.remark) new_result FROM tb_name a group by a.id
     
  • 相关阅读:
    广播系统android安全:flag FLAG_RECEIVER_REGISTERED_ONLY的意义
    产品类大话设计模式——简单工厂模式
    打印数组算法:堆栈与深度优先搜索(迷宫问题)
    函数声明第四章利用函数实现指定的功能
    构造函数调用C++ 类和动态内存分配
    命令密码MySQL忘记密码恢复密码的实现方法
    线程资源PHP源码分析之线程安全模型
    编译类【COCOS2DXLUA 脚本开发之十四】解决自定义CPP类通过TOLUA++ BINDING LUACOCOS2D后编译到ANDROID运行黑屏(没有调用自定义CPP类)的问题!
    语句数据库ubuntu下mysql的常用命令
    eclipse中配置tomcat
  • 原文地址:https://www.cnblogs.com/alsf/p/6217838.html
Copyright © 2011-2022 走看看