<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    我為你狂
    為你而瘋狂
    posts - 29,comments - 9,trackbacks - 0
    怎么合并多行記錄的字符串,一直是oracle新手喜歡問的SQL問題之一,關于這個問題的帖子我看過不下30個了,現在就對這個問題,進行一個總結。
       什么是合并多行字符串(連接字符串)呢,例如:
    SQL> desc test;
    Name    Type         Nullable Default Comments 
    ------- ------------ -------- ------- -------- 
    COUNTRY VARCHAR2(20) Y                         
    CITY    VARCHAR2(20) Y                         

    SQL> select * from test;

    COUNTRY              CITY
    -------------------- --------------------
    中國                 臺北
    中國                 香港
    中國                 上海
    日本                 東京
    日本                 大阪
    要求得到如下結果集:
    -------    --------------------
    中國       臺北,香港,上海
    日本       東京,大阪
      實際就是對字符實現一個聚合功能,我很奇怪為什么Oracle沒有提供官方的聚合函數來實現它呢:)
      下面就對幾種經常提及的解決方案進行分析(有一個評測標準最高★★★★★):
    1.被集合字段范圍小且固定型 靈活性★   性能★★★★ 難度 ★
      這種方法的原理在于你已經知道CITY字段的值有幾種,且還不算太多,如果太多這個SQL就會相當的

    長。。看例子:
    SQL> select t.country,
      2  MAX(decode(t.city,'臺北',t.city||',',NULL)) ||
      3  MAX(decode(t.city,'香港',t.city||',',NULL))||
      4  MAX(decode(t.city,'上海',t.city||',',NULL))||
      5  MAX(decode(t.city,'東京',t.city||',',NULL))||
      6  MAX(decode(t.city,'大阪',t.city||',',NULL))
      7  from test t GROUP BY t.country
      8  /

    COUNTRY              MAX(DECODE(T.CITY,'臺北',T.CIT
    -------------------- ------------------------------
    中國                 臺北,香港,上海,
    日本                 東京,大阪,
      大家一看,估計就明白了(如果不明白,好好補習MAX DECODE和分組)。這種方法無愧為最笨的方法

    ,但是對某些應用來說,最有效的方法也許就是它。
    2.固定表固定字段函數法 靈活性★★ 性能★★★★ 難度 ★★
      此法必須預先知道是哪個表,也就是說一個表就得寫一個函數,不過方法1的一個取值就要便捷多了。在大多數應用中,也不會存在大量這種合并字符串的需求。廢話完畢,看下面:
      定義一個函數
    create or replace function str_list( str_in in varchar2 )--分類字段
      return varchar2
    is
          str_list  varchar2(4000) default null;--連接后字符串
          str  varchar2(20) default null;--連接符號
    begin
          for x in ( select TEST.CITY from TEST where TEST.COUNTRY = str_in ) loop
              str_list := str_list || str || to_char(x.city);
              str := ', ';
          end loop;
          return str_list;
    end;
    使用:
    SQL> select DISTINCT(T.country),list_func1(t.country) from test t;

    COUNTRY              LIST_FUNC1(T.COUNTRY)
    -------------------- ----------------
    中國                 臺北, 香港, 上海
    日本                 東京, 大阪

    SQL> select t.country,str_list(t.country) from test t GROUP BY t.country;

    COUNTRY              STR_LIST(T.COUNTRY)
    -------------------- -----------------------
    中國                 臺北, 香港, 上海
    日本                 東京, 大阪
    這個時候,使用分組和求唯一都可以滿足要求。它的原理就是,根據唯一的分組字段country,在函數里面再次查詢該字段對應的所有被合并列,使用PL/SQL將其合并輸出。
    3.靈活表函數法 靈活性★★★ 性能★★★ 難度 ★★★
      該方法是在方法2的基礎上,使用動態SQL,將表名和字段名稱傳入,從而達到靈活的目的。
      create or replace function str_list2( key_name in varchar2,
                        key  in varchar2,
                        coname in varchar2,
                        tname     in varchar2 )
     return varchar2
    as
        type rc is ref cursor;
        str    varchar2(4000);
        sep    varchar2(2);
        val    varchar2(4000);
        cur    rc;
    begin
        open cur for 'select '||coname||'
                        from '|| tname || '
                        where ' || key_name || ' = :x '
                    using key;
        loop
            fetch cur into val;
            exit when cur%notfound;
            str := str || sep || val;
            sep := ', ';
        end loop;
        close cur;
        return str;
    end;
    SQL> select test.country,
      2  str_list2('COUNTRY', test.country, 'CITY', 'TEST') emplist
      3  from test
      4   group by test.country
      5  /

    COUNTRY              EMPLIST
    -------------------- -----------------
    中國                 臺北, 香港, 上海
    日本                 東京, 大阪
    4.一條SQL法 靈活性★★★★ 性能★★ 難度 ★★★★
      一條SQL的法則是某位大師提出的,大家曾經在某個時期都樂此不彼的尋求各種的問題一條SQL法,但是大師的意思似乎被曲解,很多性能差,可讀性差,靈活差的SQL都是這個原則產物,所謂畫虎不成反成犬類。不過,解決問題始終是第一原則,這里還是給出一個比較有代表性的一條SQL方法。
    SELECT country,max(substr(city,2)) city
      FROM
    (SELECT country,sys_connect_by_path(city,',') city
     FROM 
    (SELECT country,city,country||rn rchild,country||(rn-1) rfather
      FROM 
      (SELECT  test.country ,test.city,row_number() over (PARTITION BY test.country ORDER BY 

    test.city) rn 
      FROM test))
    CONNECT BY PRIOR rchild=rfather START WITH rfather LIKE '%0')
     GROUP BY country;
      下面分步解析,有4個FROM,就有4次結果集的操作。
       step 1 給記錄加上序號rn
      SQL> SELECT  test.country ,test.city,row_number() over (PARTITION BY test.country ORDER 

    BY test.city) rn
      2    FROM test
      3  /

    COUNTRY              CITY                         RN
    -------------------- -------------------- ----------
    日本                 大阪                          1
    日本                 東京                          2
    中國                 上海                          1
    中國                 臺北                          2
    中國                 香港                          3
      step 2 創造子節點父節點
    SQL> SELECT country,city,country||rn rchild,country||(rn-1) rfather
      2    FROM
      3    (SELECT  test.country ,test.city,row_number() over (PARTITION BY test.country ORDER 

    BY test.city) rn
      4    FROM test)
      5  /
     日本 大阪 日本1 日本0
     日本 東京 日本2 日本1
     中國 上海 中國1 中國0
     中國 臺北 中國2 中國1
     中國 香港 中國3 中國2
      step 3 利用sys_connect_by_path生成結果集
    SELECT country,sys_connect_by_path(city,',') city
     FROM 
    (SELECT country,city,country||rn rchild,country||(rn-1) rfather
      FROM 
      (SELECT  test.country ,test.city,row_number() over (PARTITION BY test.country ORDER BY 

    test.city) rn 
      FROM test))
    CONNECT BY PRIOR rchild=rfather START WITH rfather LIKE '%0'
     日本 ,大阪
     日本 ,大阪,東京
     中國 ,上海
     中國 ,上海,臺北
     中國 ,上海,臺北,香港
      step 4 最終步驟,篩選結果集合
    SQL> SELECT country,max(substr(city,2)) city
      2    FROM
      3  (SELECT country,sys_connect_by_path(city,',') city
      4   FROM
      5  (SELECT country,city,country||rn rchild,country||(rn-1) rfather
      6    FROM
      7    (SELECT  test.country ,test.city,row_number() over (PARTITION BY test.country ORDER 

    BY test.city) rn
      8    FROM test))
      9  CONNECT BY PRIOR rchild=rfather START WITH rfather LIKE '%0')
     10   GROUP BY country;

    COUNTRY              CITY
    -------------------- -------
    中國                 上海,臺北,香港
    日本                 大阪,東京

      可謂是,7歪8搞,最后還是弄出來了,呵呵。
    5.自定義聚合函數 靈活性★★★★★ 性能★★★★★ 難度 ★★★★★
      最后一個方法是我認為“王道”的方法,自定義聚合函數。
      就如何我在本開始說的,為啥oracle沒有這種聚合函數呢?我也不知道,但oracle提供了聚合函數的

    API可以讓我方便的自己定義聚合函數。
      詳細可以看Oracle Data Catridge guide這個文檔。連接如下:
      http://www.oracle.com.cn/other/9ionlinedoc/appdev.920/a96595/toc.htm
    下面給出一個簡單的例子:
    SQL> SELECT t.country,strcat(t.city) FROM test t GROUP BY t.country;

    COUNTRY              STRCAT(T.CITY)
    -------------------- ------------------
    日本                 東京,大阪
    中國                 臺北,香港,上海
    簡單吧,和官方的函數一樣的便捷高效。
    函數:
    CREATE OR REPLACE FUNCTION strcat(input varchar2 )
    RETURN varchar2
    PARALLEL_ENABLE AGGREGATE USING strcat_type;
    TYPE:
    create or replace type strcat_type as object (
        cat_string varchar2(4000),
        static function ODCIAggregateInitialize(cs_ctx In Out strcat_type) return number,
        member function ODCIAggregateIterate(self In Out strcat_type,value in varchar2) return 

    number,
        member function ODCIAggregateMerge(self In Out strcat_type,ctx2 In Out strcat_type) 

    return number,
        member function ODCIAggregateTerminate(self In Out strcat_type,returnValue Out 

    varchar2,flags in number) return number
    )
    6.待發掘...
      總結,合并字符串還有更多的方法希望大家能發掘,本文的目的主要是拋磚引玉,如果有新的發現我會繼續更新方法。需要注意的問題是,本文采用varchar2為例子,所以長度有限制,oracle的版本對方法的實現也影響。
    posted on 2009-06-25 19:33 小虎(年輕) 閱讀(320) 評論(0)  編輯  收藏 所屬分類: Oracle相關
    主站蜘蛛池模板: A在线观看免费网站大全| 亚洲精品国产肉丝袜久久| 国产香蕉九九久久精品免费| 一级成人毛片免费观看| 亚洲国产精品专区| 亚洲中文字幕无码中文字在线| 女人被弄到高潮的免费视频| 91人人区免费区人人| 中文字幕a∨在线乱码免费看 | 国产精品亚洲精品青青青| 国产亚洲精品资源在线26u| 四虎永久免费观看| 日本免费人成黄页网观看视频| 中文字幕亚洲免费无线观看日本| 国产精品一区二区三区免费| 国内成人精品亚洲日本语音 | 成人免费视频一区二区三区| 18女人毛片水真多免费| 拍拍拍无挡视频免费观看1000| 午夜在线免费视频| 国产成人高清亚洲一区91| 亚洲中文字幕无码久久| 亚洲av无码国产综合专区| 久久精品国产亚洲AV香蕉| 亚洲伦另类中文字幕| 亚洲国产第一站精品蜜芽| 国产亚洲免费的视频看| 亚洲性久久久影院| 亚洲一区精品伊人久久伊人| 久久久久一级精品亚洲国产成人综合AV区 | 99久久久精品免费观看国产| 91精品国产免费入口| 免费A级毛片无码A∨| 亚洲免费精彩视频在线观看| 中文字幕免费不卡二区| 久久er国产精品免费观看2| 国产精品视频全国免费观看| 免费看黄的成人APP| 久久香蕉国产线看免费| 一级毛片aaaaaa免费看| AV无码免费永久在线观看|