1. 程式人生 > >oracle 11g 行轉列的問題 decode實現與pivot實現

oracle 11g 行轉列的問題 decode實現與pivot實現

oracle 11g 行轉列的問題

舉一個簡單的例子,假設有表名為demo其中只有兩列一列為型別names,一列為數量nums。

表中資料如下:


目標統計出表中apple及orange各自的總數,在一列中顯示出來。

常規寫法:

select names,sum(nums) from demo group by names;

group完的結果如下:

要轉到一行中顯示則需要使用decode函式(或者case when)。

sql及執行結果如下:


上面的寫法能夠比較直觀的看出具體邏輯。但是寫法比較複雜,此處如果利用Oracle11g提供的pivot方法可以方便的得到以上結果。寫法如下:

select *
  from (select names, nums from demo)
pivot(sum(nums)
   for names in('apple' 蘋果, 'orange' 橘子))

pivot上半部分select * from(....)括號內可以加約束條件where。povit內部in可以控制names的範圍。

使用pivot得到的結果與上面一致:

這裡如果擴充套件一下,在demo表中加入店鋪的概念,用做記錄每個店鋪每種水果賣出的數量(有的店鋪可能沒有某種水果)。

假設原始資料如下:


目標結果如下:


常規寫法:

select storeId, nvl(蘋果, 0) 蘋果, nvl(橘子, 0) 橘子, nvl(香蕉, 0) 香蕉
  from (select storeId,
               sum(decode(names, 'apple', nums)) 蘋果,
               sum(decode(names, 'orange', nums)) 橘子,
               sum(decode(names, 'banana', nums)) 香蕉
          from demo
         group by storeId);

使用pivot的寫法:

select storeId, nvl(蘋果, 0) 蘋果, nvl(橘子, 0) 橘子, nvl(香蕉, 0) 香蕉
  from (select *
          from (select storeId, names, nums from demo)
        pivot(sum(nums)
           for names in('apple' 蘋果, 'orange' 橘子, 'banana' 香蕉)))

結果一致:


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

下面是稍稍複雜點的例子:

原始資料如下:商戶號每日有不同的數量(且每個商戶可能出現某日沒有記錄的情況)


原始資料中 mcht_cd 作為商戶號,假設每個商戶在同一天內有多筆記錄,從截圖可以看出8000...10002這個商戶在20180702這一天有兩筆記錄 amount各為1,114816...28這個商戶有很多amount為2的記錄。同時每個商戶在某一天都可能沒有記錄。截圖可以看出8000...0002在20180703沒有記錄。(語言表達能力有限 可以直接看目標結果)

目標結果:按商戶號統計每日總數量


常規使用的decode的寫法可以實現行轉列

--列轉行結果   
select mcht_cd,
       nvl(s20180702s, 0) s20180702s,
       nvl(s20180703s, 0) s20180703s,
       nvl(s20180704s, 0) s20180704s,
       nvl(s20180705s, 0) s20180705s,
       nvl(s20180706s, 0) s20180706s
  from (select mcht_cd,
               sum(decode(inst_date, '20180702', amount)) s20180702s,
               sum(decode(inst_date, '20180703', amount)) s20180703s,
               sum(decode(inst_date, '20180704', amount)) s20180704s,
               sum(decode(inst_date, '20180705', amount)) s20180705s,
               sum(decode(inst_date, '20180706', amount)) s20180706s
          from txn_info
         where id >= 807010000000000000
           and id < 807070000000000000
           and stat = '8'
         group by mcht_cd)

其中中間紅色部分sql可以得到如下統計結果,當某商戶某日沒有記錄時統計結果為空


目標將上面的結果中的空去掉,此時只需在外面套一層nvl即可的出最終統計結果,統計結果如下:


oracle 11g 提供pivot函式可以直接得到以上結果

select *
          from (select mcht_cd, inst_date, amount
                  from tx_info
                 where id >= 807010000000000000
                   and id < 807130000000000000
                   and stat = '8')
        pivot(sum(amount)
           for inst_date in('20180702' s20180702s,
                           '20180703' s20180703s,
                           '20180704' s20180704s,
                           '20180705' s20180705s,
                           '20180706' s20180706s))

統計結果如下


如果要去除其中的空欄位只需要在外部套一層nvl函式即可。

具體程式碼如下:

select mcht_cd,
       nvl(s20180702s, 0) s20180702s,
       nvl(s20180703s, 0) s20180703s,
       nvl(s20180704s, 0) s20180704s,
       nvl(s20180705s, 0) s20180705s,
       nvl(s20180706s, 0) s20180706s
  from ( select *
           from (select mcht_cd, inst_date, amount
                  from gtx_info
                 where id >= 807010000000000000
                   and id < 807130000000000000
                   and stat = '8')
        pivot(sum(amount)
           for inst_date in('20180702' s20180702s,
                           '20180703' s20180703s,
                           '20180704' s20180704s,
                           '20180705' s20180705s,
                           '20180706' s20180706s))   );
最終結果如下: