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可以正常使用