Excel 表間關聯運算的示例

用 Excel 處理數據時,經常會涉及到多頁 sheet 數據之間的關聯運算需求,用 vlookup 可以完成部分簡單關聯,但較複雜的情況時仍然不太方便,常常需要多次操作才能完成。另外,當要做關聯的文件比較多,需要批量處理時,雖然可以藉助 VBA 來實現,但 VBA 不是個專門爲結構化計算設計,實現計算非常繁瑣。這裏給出一些關聯運算的示例,分析解決方法並給出 SPL 代碼。SPL 是專業計算引擎 esProc 使用的語言,用於處理結構化數據運算非常方便,比 vlookup 及 VBA 更簡單。

一、引用複製其它頁的列

現有從財務部獲取的員工工資表(EMPLOYEE 頁),但是其中的部門信息只有部門編號(DEPARTID 列),不方便閱讀和出報表。從人事部獲取到部門信息表(DEPARTMENT 頁)後,需要將員工工資表的 DEPARTID, 逐一到部門信息表中查找到對應的 ID,然後複製部門名稱(DEPARTMENT 列)到員工工資表。

文件 salary.xlsx 中數據如下:

..

..

目標結果:

..

這是最簡單的關聯,採用 vlookup 函數可以實現,但仍有些注意事項。vlookup 函數在做查找時,必須清楚地知道要返回列和查找列的相對位置,如果中間插入刪除了列,就需要調整公式;而且還要求被查找列必須位於區域的首列,當返回列在查找列的前面時,要對數據列先做次序調整才能用。

SPL 按列名訪問,沒有這些問題:

  A B
1 =file("salary.xlsx").xlsimport@t() /導入第一頁的帶標題工資表
2 =file("salary.xlsx").xlsimport@t(;"DEPARTMENT") /導入 DEPARTMENT 工作頁的部門表
3 =A1.join(DEPARTID,A2:ID,DEPARTMENT) /採用序表外鍵關聯方法,用工資表的 DEPARTID 字段關聯部門表 (A2) 的 ID,並選出 DEPARTMENT 字段
4 =file("out.xlsx").xlsexport@t(A3) /將關聯好的結果寫出到另一文件

二、多列匹配

如果獲取到的文件數據中不包含某種 ID 主鍵時,則需要根據多個列來做匹配。如下的學生成績單,學生的姓和名是分開的列。現在需要根據姓和名,查找出每個學生的所屬班級,以方便根據班級統計各班的成績。

文件 scores.xlsx 中數據如下:

..

..

目標結果:

..

使用 vlookup 函數時,被查找的數據必須位於指定範圍的第一列,也就是次序很重要,且一次只能查找一個值。像這樣的多列匹配,沒法直接使用 vlookup,需要過渡的辦法。比如將要查找的列用 textjoin 合併到一個輔助列,目的表也得做同樣的合併。最後再通過輔助列來查找,而這些查找前的準備工作,使得複雜度又更上一層樓。

SPL 不需要構成中間輔助列,直接用多個查找列名即可:

  A B
1 =file("scores.xlsx").xlsimport@t() /導入第一頁的帶標題分數表
2 =file("scores.xlsx").xlsimport@t(;"Sheet2") /導入 Sheet2 工作頁的班級表
3 =A1.join(FirstNames:LastNames,A2:FirstNames:LastNames,Class) /採用序表外鍵關聯方法,用分數表的 FirstNames 和 LastNames 字段關聯班級表的對應字段,並選出 Class 字段
4 =file("out.xlsx").xlsexport@t(A3)  

三、一對一的匹配

一個寬表的字段過多時,爲了存儲以及檢索效率,往往需要將字段拆分到主鍵相同的多個小表中。如下的職員表跟生日表都是小表,現在需要通過 ID 字段來關聯,方便查看員工的整體信息。

文件 employee.xlsx 中數據如下:

..

..

目標結果:

..

採用 vlookup 處理一對一關聯時,複雜度跟前面的多對一是一樣的,仍然有位置問題。但一對一關聯的表有時會多於兩個時,vlookup 函數沒法同時處理多個表關聯,只能一個一個來,稍顯繁瑣。

SPL 可以一次處理多個表和多個關聯列:

  A B
1 =file("employee.xlsx").xlsimport@t() /導入第一頁的帶標題員工表
2 =file("employee.xlsx").xlsimport@t(;"BIRTHDAY") /導入 BIRTHDAY 頁的生日表
3 =join(A1:Employee,ID;A2:Birthday,ID).new(Employee.ID,Employee.NAME,Employee.SSN,Birthday.Birthday) /採用多序表關聯,匹配兩個表的 ID 字段後,併產生所需字段的新序表
4 =file("out.xlsx").xlsexport@t(A3)  

       注意跟前面的 A.join 不同,這裏關聯好的結果要用 new 方法選出關注的字段。

 

       vlookup 只能依據左邊的數據爲準,即所謂的左連接,意思是當關聯表數據有缺失(找不到可關聯數據時)用空值填充。但一對一匹配時,我們有時還希望獲得內連接和全連接的效果。所謂內連接,即指將關聯不上的數據刪除掉,只保證可以關聯上的數據,如果用 vlookup 實現,就需要在關聯後將有空值的數據行刪除。而全連接是指如果被關聯表有數據在關聯表中找不到,也需要抄錄過來,vlookup 無法直接實現了,只能分別做關聯,然後合併,再去除重複數據,非常繁瑣。

文件 employees.xlsx 中數據如下:

....

查看上面的數據,員工表缺失了21121,73769,17991;生日表缺失了 22373,26832。

1.      左連接

現在要實現左連接,也即沒填寫生日的記錄也保留,目標結果爲:

..

在 SPL 中實現左連接,只需加上選項 1。將上面代碼中 A3 改爲:

=join@1(A1:Employee,ID;A2:Birthday,ID).new(Employee.ID,Employee.NAME,Employee.SSN,Birthday.Birthday)

2.      內連接

join 函數缺省選項時,就是內連接,內連接僅包含兩邊都匹配的數據。

目標結果:

..

內連接時,A3 中 SPL 代碼爲:

=join(A1:Employee,ID;A2:Birthday,ID).new(Employee.ID,Employee.NAME,Employee.SSN,Birthday.Birthday)

3.      右連接

也即保留所有生日表中的記錄,目標結果爲:

..

實現右連接,其實就是將源和目標對調後的左連接,注意右連接時,選出的 ID 號要從右表 Birthday 中獲取,否則就爲空了,所以 A3 中的 SPL 代碼爲:

=join@1(A2:Birthday,ID;A1:Employee,ID).new(Birthday.ID,Employee.NAME,Employee.SSN,Birthday.Birthday)

4.      全連接

全連接相當於左右連接的並集,目標結果爲:

..

全連接時,使用選項 f,注意此時的 ID 需要用表達式從非空的表中獲取,所以 A3 中的 SPL 代碼爲:

=join@f(A2:Birthday,ID;A1:Employee,ID).new(if(Birthday==null,Employee.ID,Birthday.ID):ID,Employee.NAME,Employee.SSN,Birthday.Birthday)

四、一對多的匹配

業務場景中常見的訂單,通常會是一個訂單下面有多個明細。也就是這類匹配中的一條訂單記錄會對應多條明細記錄,屬於一對多的關聯。如下的訂單跟明細數據,現在需要將每個訂單和明細用 OrderID 關聯起來,方便用時間維度來統計訂單的總額。

文件 orders.xlsx 的數據:

..

..

目標結果:

..

由於 vlookup 只能以左邊數據爲基準,而像這類一對多的關聯,需要匹配後添加記錄,所以沒法實現左連接。而如果是做內連接的話,倒是可以將明細當源表,精確匹配後,再去掉訂單爲空的記錄。又因爲沒法實現左連接,所以全連接也沒法實現。

SPL 指定關聯字段,不用考慮對應關係,便可關聯:

  A B
1 =file("orders.xlsx").xlsimport@t() /導入第一頁的帶標題訂單表
2 =file("orders.xlsx").xlsimport@t(;"DETAIL") /導入 DETAIL 頁的明細表
3 =join(A1,OrderID;A2,OrderID).new(_1.OrderID,_1.OrderDate,_2.ProductID,_2.Quantity,_2.UnitPrice) /關聯相應字段,並選出關注的字段產生新序表
4 =file("out.xlsx").xlsexport@t(A3)  

一對多和一對一的關聯方法一樣,也是用多表關聯方法 join,且同樣只需簡單指定關聯字段名,所以對於左連接、右連接等不同連接方式,都跟第三節一樣,這裏不再贅述。

 

五、非等值匹配

前面例子中,不管是哪種對應方式,都是根據條件相等去匹配。實際應用中,還有按非相等條件來匹配的情形。比如第二節中的成績表,現在需要根據分數段來評級,此時沒法直接用分數去目的表中做相等匹配。

評級數據表如下:

..

目標結果:

..

拋開關聯的條件是按照相等還是範圍來匹配,這種關聯類似於第一節的多對一關聯。用 vlookup 函數時,需要先將分段值按升序排好序,然後再用模糊匹配方式,來實現按範圍匹配。

SPL 也提供了非等值連接:

  A B
1 =file("scores.xlsx").xlsimport@t() /導入第一頁的帶標題成績表
2 =file("scores.xlsx").xlsimport@t(;"Sheet3") /導入 Sheet3 頁的評級表
3 =xjoin(A1:Score;A2:Level,A2.From<Score.Score   && Score.Score<A2.To) /使用叉乘關聯 xjoin,再用過濾條件留下符合要求的匹配
4 =A3.new(Score.FirstNames,Score.LastNames,Score.Subject,Score.Score,Level.Level) /匹配完成後,產生包含所需字段的新序表
5 =file("out.xlsx").xlsexport@t(A4)  

可以使用完全叉乘方法 xjoin,然後再用過濾條件去掉不合要求的匹配。

 

SPL Cookbook》中有更多相關計算示例。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章