自定義函數實現列轉行效果

来源:http://www.cnblogs.com/hanzongze/archive/2017/06/22/oracle-wm_concat.html
-Advertisement-
Play Games

在 Oracle 領域,我相信一說到列轉行大部分人都會立馬想到 WM_CONCAT 函數,我覺得主要是因為該函數比較實用。但事實上 WM_CONCAT 並非官方公開函數,使用會存在一定的風險;函數返回值的格式比較單一(只能用逗號分割);返回值的長度也限制。 在 "《.Net程式員學用Oracle系列 ...


在 Oracle 領域,我相信一說到列轉行大部分人都會立馬想到 WM_CONCAT 函數,我覺得主要是因為該函數比較實用。但事實上 WM_CONCAT 並非官方公開函數,使用會存在一定的風險;函數返回值的格式比較單一(只能用逗號分割);返回值的長度也限制。

《.Net程式員學用Oracle系列(20):層次查詢(CONNECT BY)》一文中,詳細講解了 WM_CONCAT 函數的用法。如果不用 WM_CONCAT 函數又該如何實現列轉行呢?當數據類別比較少的時候,通過 CASE 判斷或 UNION ALL 查詢也能實現效果,但問題就是寫法太死板,不過一般也沒人會這麼乾。本文接下來會介紹兩個自定義函數分別來實現列轉行的聚合效果。

第一個自定義函數主要是輔以 COLLECT 函數來實現的,我在回答一個園友的問題時列出了實現步驟,查看該問題。下麵是我重新整理後的版本:

第 1 步(創建類型 type_table_string,用於轉換 COLLECT 函數的返回值):

CREATE OR REPLACE TYPE type_table_string IS TABLE OF VARCHAR2(4000);

第 2 步(創建函數 fn_to_string,用於將 type_table_string 類型轉換成普通字元串):

CREATE OR REPLACE FUNCTION fn_to_string(
  p_str_tab IN type_table_string,
  p_separator IN VARCHAR2 DEFAULT ','
)
RETURN VARCHAR2 IS
  v_ret_str VARCHAR2(4000);
BEGIN
  FOR i IN 1..p_str_tab.COUNT LOOP
    v_ret_str:=v_ret_str||p_separator||p_str_tab(i);
  END LOOP;
  RETURN LTRIM(v_ret_str,p_separator);
END;

調用方法:

SELECT t.dept_code,fn_to_string(CAST(COLLECT(t.staff_name) AS type_table_string),'|') staff_names
FROM demo.t_staff t GROUP BY t.dept_code;

調用結果:

DEPT_CODE                        STAFF_NAMES
-------------------------------- ----------------------------------------------
010101                           小明|小強|王二
010102                           小林|小薩
010103                           韓三|小玲
010104                           小梅|小燕
010201                           小軍|小芳|小紅
010202                           小飛

第二個自定義函數在百度中輸入“zh_concat”就能找到一堆的參考,我有嘗試尋找 zh_concat 函數的出處,但網上的翻版實在太多,而且大部分比較無恥(沒寫出處),結果就是我沒能找到該函數的出處,因此在這裡我也沒法兒給出 zh_concat 函數的出處了。

我找到的那些有關 zh_concat 函數的帖子內容普遍比較混亂,於是我決定整理出一個更加清晰、整潔和美觀的版本,以便閱讀和理解,具體如下:

第 1 步(創建類型 type_concat 的定義):

CREATE OR REPLACE TYPE type_concat
AUTHID CURRENT_USER AS OBJECT(
  v_result_string VARCHAR2(4000),
  STATIC FUNCTION odciAggregateInitialize(
    concat IN OUT type_concat) RETURN NUMBER,
  MEMBER FUNCTION odciAggregateIterate(
    SELF IN OUT type_concat,str IN VARCHAR2) RETURN NUMBER,
  MEMBER FUNCTION odciAggregateTerminate(
    SELF IN type_concat,return_value OUT VARCHAR2,flags IN NUMBER) RETURN NUMBER,
  MEMBER FUNCTION odciAggregateMerge(
    SELF IN OUT type_concat,concat IN type_concat) RETURN NUMBER
);

第 2 步(創建類型 type_concat 的 body):

CREATE OR REPLACE TYPE BODY type_concat
IS
  STATIC FUNCTION odciAggregateInitialize(concat IN OUT type_concat)
  RETURN NUMBER IS
  BEGIN
    concat := type_concat(NULL);
    RETURN ODCICONST.SUCCESS;
  END;
  
  MEMBER FUNCTION odciAggregateIterate(SELF IN OUT type_concat,str IN VARCHAR2)
  RETURN NUMBER IS
  BEGIN
    IF SELF.v_result_string IS NOT NULL THEN
      SELF.v_result_string := SELF.v_result_string||','||str;
    ELSE
      SELF.v_result_string := str;
    END IF;
    RETURN ODCICONST.SUCCESS;
  END;
  
  MEMBER FUNCTION odciAggregateTerminate(SELF IN type_concat,return_value OUT VARCHAR2,flags IN NUMBER)
  RETURN NUMBER IS
  BEGIN
    return_value := SELF.v_result_string;
    RETURN ODCICONST.SUCCESS;
  END;
  
  MEMBER FUNCTION odciAggregateMerge(SELF IN OUT type_concat,concat IN type_concat)
  RETURN NUMBER IS
  BEGIN
    IF concat.v_result_string IS NOT NULL THEN
      SELF.v_result_string := SELF.v_result_string||','||concat.v_result_string;
    END IF;
    RETURN ODCICONST.SUCCESS;
  END;
END;

第 3 步(創建函數 fn_concat,可替代 WM_CONCAT):

CREATE OR REPLACE FUNCTION fn_concat(str VARCHAR2)
RETURN VARCHAR2 AGGREGATE USING type_concat;

調用方法:

SELECT t.dept_code,fn_concat(t.staff_name) staff_names FROM demo.t_staff t GROUP BY t.dept_code;

調用結果:

DEPT_CODE                             STAFF_NAMES
------------------------------------- ----------------------------------------------------
010101                                小明,小強,王二
010102                                小林,小薩
010103                                韓三,小玲
010104                                小梅,小燕
010201                                小軍,小芳,小紅
010202                                小飛

說明一:上例中的 AUTHID CURRENT_USER 是許可權控制的關鍵字,表示調用者許可權,即當前用戶。預設為 AUTHID DEFINER,表示定義者許可權,即模式擁有者。

說明二:將 type_concat 中 v_result_string 和 return_value 的類型改為 CLOB 類型,並將 fn_concat 的返回值類型也改為 CLOB,就成了 CLOB 版的 fn_concat 了。

本文鏈接http://www.cnblogs.com/hanzongze/p/oracle-wm_concat.html
版權聲明:本文為博客園博主 韓宗澤 原創,作者保留署名權!歡迎通過轉載、演繹或其它傳播方式來使用本文,但必須在明顯位置給出作者署名和本文鏈接!個人博客,能力有限,若有不當之處,敬請批評指正,謝謝!


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • create table DEPT ( deptno NUMBER(2) not null, dname VARCHAR2(20), loc VARCHAR2(13) ); alter table DEPT add constraint PK_DEPT primary key (DEPTNO); c ...
  • 前言 - 簡單準備一下前戲 前面寫過幾篇mariadb 數據的隨筆, 多數偏C/C++層面. 這次分享一下平時開發中, 處理的一些數據層面的業務. 對於MariaDB, 不做過多介紹. 如果你有Ubuntu 系統, 可以通過下麵來個環境玩玩 這裡扯一下, 假如你複製mysql 腳本到 mariadb ...
  • 前言 最近一年由於工作需要大部分使用的都是NoSql資料庫,對關係型資料庫感覺越來越陌生,一個由 和`order by` 引發的血案由此而生。在此做個記錄,以備不時之需。 <! more 需求 首先,看一下整體的表結構。 現在查找每個 中最新的數據。 由於數據太多,不是很好看到效果。我們就拿一個 為 ...
  • 前提: 這個月的突然一天,有個項目對接需要使用axis2發佈的介面,這下難倒我了,畢竟之前我是連webservice介面都不知怎麼發佈的。後來從HelloWorld開始發佈了第一個介面--sayHi();到這一步的時候都是很順利的,唯獨和axis2整合的時候,出現問題了,spring的dao層在ax ...
  • 錯誤:Host '127.0.0.1' is not allowed to connect to this MySQL server一般原因: MySQL資料庫的配置文件my.ini中設置了參數: skip-name-resolve 從而導致使用“localhost”不能連接到資料庫。解決方法: 註 ...
  • 本文翻譯翻譯自http://hadoop.apache.org/docs/r2.8.0/hadoop-project-dist/hadoop-common/ClusterSetup.html 譯註:僅僅是翻譯,內容關於搭建一個純凈,簡單的hadoop集群。實際的集群,需要考慮高可靠,性能,安全。 參 ...
  • mysqldump 備份鑒於其自身的某些特性(鎖表,本質上備份出來insert腳本或者文本,不支持差異備份),不太適合對實時性要求比較高的情況Xtrabackup可以解決mysqldump存在的上述的一些問題,生產環境應用的也會更多一些。本文簡單測試一下Xtrabackup對MySQL資料庫的備份還 ...
  • 最近因系統雲化項目,學習使用MySQL集群,為了找一款順手的mysql客戶端,反覆使用了多個工具,並篩選出一個自認為最滿意的,在此分享。 先說我的選擇:SQLyog。 嘗試的客戶端:Toad for MySQL、MySQL-Front、Navicat for MySQL、SQLyog。 官方下載鏈接... ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...