1. 程式人生 > >Oracle 行列轉換例項 列轉行報表

Oracle 行列轉換例項 列轉行報表

簡單說明:

本博文不面向Oracle行列轉換零基礎的筒子,這是一個高階列轉行之後的報表例項:
有張表存在冗餘資料
  id1,url1
  id2,url1&url2&url3&url3&url2...
  id3,url1&url2&url3&url3&url2...
  id4,url1&url4&url5&url5...
現在要根據url進行記錄濾重,將重複出現的url對應的id查出來拼接在一起
url是不確定的,可能有上萬個url甚至更多,一條記錄中的url可能存在重複,相鄰的記錄之間的url可能是完全重複的

準備測試資料:

create table id_urls(id number,urls varchar2(255));
set define off
insert into ID_URLS values(1,'URL1');
insert into ID_URLS values(2,'URL1');
insert into ID_URLS values(3,'URL1&URL2&URL3');
insert into ID_URLS values(4,'URL1&URL2&URL3');
insert into ID_URLS values(5,'URL2&URL3&URL2'
);
insert into ID_URLS values(6,'URL2&URL3&URL2'); insert into ID_URLS values(7,'URL6&URL7&URL8&URL9&URL0'); insert into ID_URLS values(8,'URL10'); commit; set define on

查詢推導過程:

1° 將URL替換為空,檢視該欄位最多有幾個URL

select regexp_replace(urls, '[^&]+', '') from ID_URLS;
select length(regexp_replace(urls, '[^&]+'
, '')) from ID_URLS;
select max(length(regexp_replace(urls, '[^&]+', ''))) + 1 as max_len from ID_URLS; -- 最大數量至少要加1,如果URL數量最多的記錄以分隔符&為行尾,加1會導致最大URL個數比實際個數大1 -- 求出來的最大URL個數是做記錄笛卡爾積的依據 -- 比如當前記錄只有一個URL,最大URL個數為10個,那麼該行記錄會笛卡爾積10次 -- 然後將10次笛卡爾積的結果集根據&符切分出第1組到第10組,會切出9組空記錄,濾空即可解決 -- 如果求出的最大URL個數比實際小的話,則會造成切分時丟失資料 -- 比如當前記錄有10個URL,但是求出的最大URL個數為5,那麼該記錄只會笛卡爾積5次 -- 然後將5次笛卡爾積的結果集根據&符切分出第1組到第5組,就會丟失5組資料 -- 因此求出的最大URL個數比實際個數大是可以的,小是不行的 -- 只有判斷表中所有記錄包含或者不包含以&分隔符結尾的情況才能得出正好相等的最大URL個數

2° 如果要將所有的URL做列傳行的還原,至少需要每條記錄重複max_len次

with max_length as
 (select max(length(regexp_replace(urls, '[^&]+', ''))) + 1 as max_len from ID_URLS)
select level as lvl from dual connect by level <= (select max_len from max_length);

3° 每條記錄都重複max_len次,列傳行切出來所有的URL

with max_length as
  (select max(length(regexp_replace(urls, '[^&]+', ''))) + 1  as max_len from ID_URLS),
repeat as
  (select level as lvl from dual connect by level <= (select max_len from max_length))
select id,regexp_substr(urls,'[^&]+',1,lvl) as single_url from ID_URLS,repeat order by id;

4° 因為並不是所有的記錄的URL都有max_len個,所以存在URL為空的記錄,過濾掉

with max_length as
  (select max(length(regexp_replace(urls, '[^&]+', ''))) + 1  as max_len from ID_URLS),
repeat as
  (select level as lvl from dual connect by level <= (select max_len from max_length)),
cut_url as
  (select id,regexp_substr(urls,'[^&]+',1,lvl) as single_url from ID_URLS,repeat)
select id, single_url from cut_url where single_url is not null order  by id;

5° 因為同一條記錄的URL有可能存在重複,因此需要濾重

with max_length as
  (select max(length(regexp_replace(urls, '[^&]+', ''))) + 1  as max_len from ID_URLS),
repeat as
  (select level as lvl from dual connect by level <= (select max_len from max_length)),
cut_url as
  (select id,regexp_substr(urls,'[^&]+',1,lvl) as single_url from ID_URLS,repeat)
select distinct id, single_url from cut_url where single_url is not null order  by id;

6° 檢視一下有多少URL重複,每個URL重複了多少次

with max_length as
  (select max(length(regexp_replace(urls, '[^&]+', ''))) + 1  as max_len from ID_URLS),
repeat as
  (select level as lvl from dual connect by level <= (select max_len from max_length)),
cut_url as
  (select id,regexp_substr(urls,'[^&]+',1,lvl) as single_url from ID_URLS,repeat),
distinct_record as
  (select distinct id, single_url from cut_url where single_url is not null order  by id)
select single_url,count(*) from distinct_record where single_url is not null group by single_url having count(*)>1;

7° 將重複的URL對應的ID拼接在一起,丟到需求人臉上

with max_length as
  (select max(length(regexp_replace(urls, '[^&]+', ''))) + 1  as max_len from ID_URLS),
repeat as
  (select level as lvl from dual connect by level <= (select max_len from max_length)),
cut_url as
  (select id,regexp_substr(urls,'[^&]+',1,lvl) as single_url from ID_URLS,repeat),
distinct_record as
  (select distinct id, single_url from cut_url where single_url is not null order  by id)
select single_url,to_char(wm_concat(id)) from distinct_record where single_url is not null group by single_url having count(*)>1;

收尾:

需求產生原因:

這是一個真實的生產需求,該表存的URL是圖片URL
使用者前臺頁面上傳圖片,一次上傳的圖片可能是多個
圖片上傳到第三方,第三方將上傳的圖片儲存的URL返回給後臺
因為網路原因或者第三方的BUG,造成多次將使用者的一次上傳行為返回給後臺
且返回資訊中的圖片URL存在重複
後臺未做處理直接將這些圖片URL入庫,造成了本次需求的產生

解決辦法:

後臺將收到的圖片URL存入Redis,一個圖片URL存一個KEY,一分鐘超時
當收到圖片URL時檢索Redis中的當前一分鐘內的圖片URL,如果存在則不再重複入庫
如果不存在,新建該圖片URL的KEY,設定一分鐘超時,入庫

題外話:

從解決辦法上可以明顯看出鍋到底是誰的
該難度的SQL業務開發無法寫出(他們少點BUG就謝天謝地了)
普通的維護向DBA無法寫出,專司BI報表的DBA或SQL開發能夠寫出
但是作為DBA,應當追求熟練揉捏手中資料的能力

[TOC]

相關推薦

Oracle 行列轉換例項 轉行報表

簡單說明: 本博文不面向Oracle行列轉換零基礎的筒子,這是一個高階列轉行之後的報表例項: 有張表存在冗餘資料 id1,url1 id2,url1&url2&url3&url3&url2... id3,url1

[Oracle]行列轉換(行合並與拆分)

csdn employee .net title case color trac 數據轉換 con 使用wmsys.wm_concat 實現行合並在 Oracle 中, 將某一個欄位的多行數據轉換成使用逗號風格的一行顯示。能夠使用函數 wmsys.wm_concat

oracle 行列轉換 列名數字

雙引號 oracle The 分享 -m key com pri 時間 oracle 行列轉換列名如果是數字,用雙引號包住 如下: -- 建表 create table workinfo(wid integer primary key,sid integer ,CO

Oracle 行列轉換函式pivot的使用(二)

關鍵函式pivot,其用法如下 pivot(聚合函式 for 列名 in(型別)) select * from table_name pivot(max(column_name)           

Oracle行列轉換case when then方法案例

select (select name from t_area where id=areaid) 區域, sum(case when month = '01' then money else 0 end) 一月, sum(case when month = '02' then mon

Oracle行列轉換方法彙總

函式名:wmsys.wm_concat 作用:以逗號分隔連線列的值 oracle 10g引入。使用時直接用wm_concat也可以。 以下介紹一些實際使用的狀況。介紹實際Case前先建立一個測試table和一些測試資料。 兩張表: employee,prject;

ORACLE行列轉換之字串拆分

ORACLE中將帶分隔符的字串拆分成多行,有很多方法,我將多種常見和不常見的拆分方法進行了收集整理。 通常這個操作被歸類為行列轉換的範疇。 為了方便測試,我將每一種方法封裝成一個函式,返回一個字串集合。 0.建立自定義集合型別 SQL> crea

Oracle行列轉換小結

目錄結構如下: 行轉列 列轉行 [一]、行轉列 1.1、初始測試資料 表結構:TEST_TB_GRADE Sql程式碼 create table TEST_TB_GRADE ( ID NUMBER(10) not null, USER_NAME VARCHAR2(

MySQL 行列轉換變化各種方法實現總結(行變報表統計 變行資料記錄統計等)

                前言:mysql行列變化,最難的就是將多個列變成多行,使用的比較多的是統計學中行變列,列變行,沒有找到現成的函式或者語句,所以自己寫了儲存過程,使用動態sql來實現,應用業務場景,使用者每個月都有使用記錄數錄入一張表,一個月一個欄位,所以表的欄位是動態增長的,現在需要實時統計當

Oracle轉行函式 Listagg() 語法詳解及應用例項

工作中用到一段比較複雜的SQL查詢指令碼,使用了listagg()函式實現了具有多個值的欄位的填充(即,列表聚合,list aggregation(我猜的))。說簡單點,listagg()函式可以實現多列記錄聚合為一條記錄,從而實現資料的壓縮、緻密化(data densifi

轉行-行列轉換

有多種實現方式: wmsys.wm_concat函式 也可以用decode函式實現. 11g可以 使用pivot 儲存過程實現 eg: 我現在的表如下: 產品名稱    銷售額  季度 乳酪          50     第一季度 乳酪          60    

[MySQL] 行列轉換變化各種方法實現總結(行變報表統計、變行資料記錄統計等)

前言:mysql行列變化,最難的就是將多個列變成多行,使用的比較多的是統計學中行變列,列變行,沒有找到現成的函式或者語句,所以自己寫了儲存過程,使用動態sql來實現,應用業務場景,使用者每個月都有使用記錄數錄入一張表,一個月一個欄位,所以表的欄位是動態增長的,現在需要實時統計

[MySQL] 行列轉換變化各種方法實現總結(行變報表統計、變行資料記錄統計等

前言: mysql行列變化,最難的就是將多個列變成多行,使用的比較多的是統計學中行變列,列變行,沒有找到現成的函式或者語句,所以自己寫了儲存過程,使用動態sql來實現,應用業務場景,使用者每個月都有使用記錄數錄入一張表,一個月一個欄位,所以表的欄位是動態增長的,

Oracle資料庫行顯示轉換顯示--pivot的應用

Create table tmp(types varchar(22) primary key,num int,maps int); insert into tmp (types, num, maps)values ('計劃收儲', 635, 50252909); insert into tm

oracle wm concat函式 用於轉行 逗號分隔

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

Oracle行列轉換

列轉行 原理: 內建函式 LISTAGG 實現: with tmp as ( select 1 id,'name1' name from dual union all select 2 id,'name2' name from dual uni

sqlserver轉行例項(只需要 修改其中幾個欄位 就可以直接使用)

首先建立表 CREATE TABLE [dbo].[ColumnIpParameter] (   [ColumnIp_ip] int  IDENTITY(1,1) NOT NULL,   [Columnlp_typeid] int  NULL, &

LinQ實現DataTable不定行轉 行列轉換

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="LinqDemo2.aspx.cs" Inherits="LinqDemo2" %> <!DOCTYPE html PUBLIC "-//W3C//

LinQ實現DataTable不定行轉 行列轉換,有圖

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="LinqDemo2.aspx.cs" Inherits="LinqDemo2" %>   <!DOCTYPE html PUBLIC "-//W3C//DTD

Oracle轉行函式版本不相容解決方案

業務場景 本部落格記錄一下Oracle列轉行函式在Oracle11的一些不相容問題,vm_concat在一些業務場景是必須的。不過這個函式使用要謹慎,底層實現應該也是group by等等實現的,效能並不是特別好。這個函式在Oracle12是沒有的,在Oracle11是不太相容的,Oracle10可以正常使用