天天看點

建議收藏丨sql行轉列的一千種寫法!!

大家好,我是明月十四橋!!

愛好特長:

1、愛好和特長有很多,擅長word、excel、ppt、wind等軟體的安裝與解除安裝;

2、精通PE、PS、PB、DCF、PEG等單詞的拼寫;

3、熟悉Windows、Linux、Mac、Android、IOS、WP8等系統的開關機。

今日重點:

   ① 花裡胡哨、不擇手段的sql寫法;

   ② 一個深度回答,把面試官征服。

白天工作晚上寫文,嘔心瀝血整理,有問題歡迎評論,點贊、收藏、評論是對我最大的支援!!!

目錄

​​一 緣起​​

​​二 火花​​

​​2.1 内置函數實作行轉列​​

​​2.2 經典case when實作​​

​​2.3 Python groupby 實作列轉行​​

​​2.4 Python pandas 實作列轉行​​

​​2.5 execl 資料透視表實作行轉列​​

​​2.6 Java 實作行轉列​​

​​2.7 hive sql實作行轉列​​

​​2.8 Teradata UDF實作行轉列​​

​​三 闌尾​​

一 緣起

在我們熱愛的《資料倉庫交流群》裡發生了一幕:

建議收藏丨sql行轉列的一千種寫法!!
建議收藏丨sql行轉列的一千種寫法!!

:請教大佬們 這個咋搞?

              那9個字,猶如一聲驚雷,在這個熱情的群裡炸開了鍋...

建議收藏丨sql行轉列的一千種寫法!!

:大佬們紛紛按奈不住(尤其是我),看不得别人有問題,我心急如焚,一是擔心這位小哥哥面試受挫,二是這麼好的學de習se的機會,我一定要把握住。。

建議收藏丨sql行轉列的一千種寫法!!

大佬1: 這位來自上海的大佬,首先給出了orcale自帶函數的解法... 

建議收藏丨sql行轉列的一千種寫法!!

大佬2: 基于orcale自帶函數的局限性,大佬2提出了适用于mysql、oracle、hive的case when寫法... 

建議收藏丨sql行轉列的一千種寫法!!

大佬3: hive 進階函數(花裡胡哨起來了)...

問題:

建議收藏丨sql行轉列的一千種寫法!!

ps.哈哈哈哈,這不就是10次面試9次問的行轉列嘛~

讨論過程中:

大佬們紛紛谏言獻策,集思廣益。

建議收藏丨sql行轉列的一千種寫法!!

二 火花

2.1 内置函數實作行轉列

原理

建議收藏丨sql行轉列的一千種寫法!!
SELECT *
FROM student
PIVOT (
 SUM(score) FOR subject IN (國文, 數學, 英語)
)   #預設按照score和subject以外其它字段進行group by      

結果展示

建議收藏丨sql行轉列的一千種寫法!!

2.2 經典case when實作

使用case when來依條件分列是最簡單的一種方法。

select 學生号,  
sum(case 科目 when '國文' then 成績 end) as 國文,  
sum(case 科目 when '數學' then 成績 end) as 數學,  
......  
from table  
where ...  
group by 學生号      

case when進階,動态列數行轉列:

但是,轉換後列數不固定的情況下呢?對照上面的例子來說就是,假設我并不知道學生學了哪些科目的時候應該怎麼做?

我們繼續用case when,但是由于列的不固定,需要先根據條件分支産生的可能性來拼接一下語句再動态執行。直接上碼看效果可能更清晰一點:

declare @sql varchar(4000)  
set @sql = 'select 學生号'  
  
select @sql = @sql + ',sum(case 科目 when '''+科目+''' then  成績 end) ['+科目+']'  
from (select distinct 科目 from table  ) as a  
order by 科目  
   
select @sql = @sql+' from table  group by 學生号'  
  
--print @sql  
exec(@sql)      

2.3 Python groupby 實作列轉行

df_new = df_new.groupby(by='電影名', as_index=False).agg("/".join)

print(df_new)      

2.4 Python pandas 實作列轉行

import pandas as pd

df = pd.DataFrame([['夏洛特煩惱','沈騰/馬麗/尹正/艾倫/王智'],
                   ['縫紉機樂隊','大鵬/喬杉/古力娜紮/李鴻其/韓童生']],
                  columns=['電影名','部分演員'])
print(df)

# 根據'/'拆分為清單
df['部分演員'] = df['部分演員'].str.split("/")      # 轉成清單
print(df)

df_new = df.explode('部分演員')
print(df_new)      

2.5 execl 資料透視表實作行轉列

Excel 要實作行列轉換,需要用到 Power Query,而Power Query 隻有Excel 2016以上的版本才有!

第一步,【Ctrl A 全選資料】-【資料】-【從表格】,建立 Power Query,進入 Power Query界面。

第二步,添加輔助列。Excel 實作列轉換,可以通過【添加輔助列】來實作該效果。而在 Power Query 有多種可以添加輔助列的方法。此處介紹兩種方法法一,通過自定義列,添加輔助列法二,通過重複列,實作添加輔助列

第三步,進行透視列。【透視列】>【值列,自定義,選中需要透視的列】-【聚合值函數,選擇不要聚合】-【确定】。

第四步,合并列。選中透視出來的列,右鍵,【合并列】-【自定義分隔符】-【确定】 。

最後,選中多餘的列,删除!再進行【關閉并上載】。全部搞定!列轉行後的資料

建議收藏丨sql行轉列的一千種寫法!!
建議收藏丨sql行轉列的一千種寫法!!

2.6 Java 實作行轉列

public class Row2Line {
 
    public static void main(String[] args) throws IntrospectionException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {  
        //你提供的對象清單,需要轉換的原資料 
        List<StudentGrand> StudentGrandList = getStudentGrandList();  
        //實作行轉列的算法
        List<List<String>> convertedTable = convert(StudentGrandList);
        //列印轉換後的集合,檢視結果
        print(convertedTable);  
        //剩下的可以根據實際需求,将轉換好的集合傳給前端、或随意處理
    }  
  
    private static List<List<String>> convert(List<StudentGrand> StudentGrandList)  
            throws IntrospectionException, IllegalAccessException, InvocationTargetException {//取得StudentGrand的屬性,當然你也可以用list = {"id", "name", ...}  
        Field[] declaredFields = StudentGrand.class.getDeclaredFields();
          
        List<List<String>> convertedTable = new ArrayList<List<String>>();  
          
        //多少個屬性表示多少行,周遊行  
        for (Field field : declaredFields) {
            field.setAccessible(true);  
            ArrayList<String> rowLine = new ArrayList<String>();
            //list<T>多少個StudentGrand實體類表示有多少列,周遊列
            for (int i = 0, size = StudentGrandList.size(); i < size; i++) {
                //每一行的第一列對應StudentGrand字段名  
                //是以新table的第一列要設定為字段名
                if(i == 0){  
                    rowLine.add(field.getName());  
                }  
                //新table從第二列開始,某一列的某個值對應舊table第一列的某個字段
                else{  
                    StudentGrand StudentGrand = StudentGrandList.get(i);  
                    String val = (String) field.get(StudentGrand);//grand為int會報錯
                    System.out.println(val);
                    rowLine.add(val);  
                }  
            }  
            convertedTable.add(rowLine);  
        }  
        return convertedTable;  
    }
    //測試用資料,實際應該從資料庫查詢,傳過來的
    private static List<StudentGrand> getStudentGrandList () {  
        List<StudentGrand> list = new ArrayList<StudentGrand>();
        list.add(new StudentGrand("001", "toni", "國文", "98"));
        list.add(new StudentGrand("001", "toni", "數學", "98"));
        list.add(new StudentGrand("001", "toni", "外語", "98"));
        list.add(new StudentGrand("001", "toni", "體育", "98"));
        list.add(new StudentGrand("006", "amy", "國文", "98"));
        list.add(new StudentGrand("006", "amy", "數學", "98"));
        list.add(new StudentGrand("006", "amy", "外語", "98"));
        list.add(new StudentGrand("006", "amy", "體育", "98"));
        list.add(new StudentGrand("003", "安東尼", "國文", "98"));
        list.add(new StudentGrand("003", "安東尼", "數學", "98"));
        list.add(new StudentGrand("003", "安東尼", "外語", "98"));
        list.add(new StudentGrand("003", "安東尼", "體育", "98"));
        return list;  
    }  
    //列印檢視結果
    private static void print(List<List<String>> convertedTable) {
        //String json = JSONArray.formObject(convertedTable).toString();
        for (List<String> list : convertedTable) { 
            for (String string : list) {
                System.out.print(string+"  ");  
            }  
            System.out.println();  
        }  
    }      

2.7 hive sql實作行轉列

使用函數:concat_ws(',',collect_set(column))  壓縮到一行,跟題目要求稍有差異。

select user_id,
concat_ws(',',collect_list(order_id)) as order_value 
from col_lie
group by user_id      

2.8 Teradata UDF實作行轉列

還是壓縮到一行,不如case when的展示效果

REPLACE FUNCTION tdstats.UDFCONCAT
  (aVarchar VARCHAR(128) CHARACTER SET UNICODE)
 RETURNS VARCHAR(10000) CHARACTER SET UNICODE
 CLASS AGGREGATE (20000)
 SPECIFIC udfConcat
 LANGUAGE C
 NO SQL
 NO EXTERNAL DATA
 PARAMETER STYLE SQL
 NOT DETERMINISTIC
 CALLED ON NULL INPUT
 EXTERNAL NAME 'SL!staudf!F!udf_concatvarchar'      
建議收藏丨sql行轉列的一千種寫法!!

三 闌尾

剩下992種包含python、java、C, if else實作之類的方法,請大家自行腦補,歡迎在評論區發表你的高見~