學會這些“套路”,excel 合併彙總都不是事

1.  問題背景

在日常工作中我們經常遇到具有相同表頭的 Excel 文件,需要將它們合併到同一個工作表中再進行分析。當文件比較多時,手工合併表格通常是件很麻煩的事情,而如果數據量很大,用 Excel 自帶的 VBA 來處理也會經常卡死。今天我就來分享一個專業的外部數據工具——集算器,掌握了集算器處理 Excel 多表合併的方法,就不用再編寫複雜且低效的 VBA 代碼了,簡單的幾行 SPL(Structured Process Language,結構化過程處理語言)代碼就能輕鬆搞定 Excel 文件合併,即使文件再多、再大也不用擔心。

2.  基本合併

A.  同一個 excel 中的多表合併

下面的例子是一個包含了銷售數據的 excel 文件,其中包含了按月劃分的 3 個結構相同的 sheet 工作表,數據如下:  

january_2013:

Customer ID

Customer Name

Invoice Number

Sale Amount

Purchase Date

1234

John Smith

100-0002

$1,200.00

2013/1/1

2345

Mary Harrison

100-0003

$1,425.00

2013/1/6

3456

Lucy Gomez

100-0004

$1,390.00

2013/1/11

4567

Rupert Jones

100-0005

$1,257.00

2013/1/18

5678

Jenny Walters

100-0006

$1,725.00

2013/1/24

6789

Samantha Donaldson

100-0007

$1,995.00

2013/1/31

february_2013:

Customer ID

Customer Name

Invoice Number

Sale Amount

Purchase Date

9876

Daniel Farber

100-0008

$1,115.00

2013/2/2

8765

Laney Stone

100-0009

$1,367.00

2013/2/8

7654

Roger Lipney

100-0010

$2,135.00

2013/2/15

6543

Thomas Haines

100-0011

$1,346.00

2013/2/17

5432

Anushka Vaz

100-0012

$1,560.00

2013/2/21

4321

Harriet Cooper

100-0013

$1,852.00

2013/2/25

march_2013:

Customer ID

Customer Name

Invoice Number

Sale Amount

Purchase Date

6634

Poop Smith

100-0014

$1,350.00

2013/3/4

8765

Tony Song

100-0015

$1,167.00

2013/3/8

2345

Mary Harrison

100-0016

$1,789.00

2013/3/17

6543

Rachel Paz

100-0017

$2,042.00

2013/3/22

3456

Lucy Gomez

100-0018

$1,511.00

2013/3/28

4321

Susan Wallace

100-0019

$2,280.00

2013/3/30

在合併3個sheet的同時,我們還可以同時從每個sheet中篩選出字段Customer Name, Sale Amount。最後的效果如下:

Customer Name

Sale Amount

John Smith

1200

Mary Harrison

1425

Lucy Gomez

1390

Rupert Jones

1257

Jenny Walters

1725

.......

........

Susan Wallace

2280

 

集算器SPL腳本:


A

1

=file(”D:/sales_2013.xlsx”).xlsopen()

2

=A1.conj(A1.xlsimport@t('Customer   Name','Sale Amount';~.stname))

3

>file(“D:/result_2013.xlsx”).   xlsexport@t(A2;"merge_sheets")


腳本說明:

A1:打開指定的 excel 文件,創建一個由多個 sheet 工作表組成的序列。

A2:利用 conj 函數遍歷 A1 序列中所有的成員工作表,導入每個工作表中指定列'Customer Name','Sale Amount',並將數據併合並。其中 xlsimport 函數導入指定列,最後一列用分號; 隔開。 參數~.stname表示指定當前工作表,由於在 conj 函數的循環中,所以就可以逐個導入所有工作表。同時,xlsimport 使用選項@t指明將工作表的第一行記錄作爲字段名。

A3:將序表 A2 作爲一個新的工作表“merge_sheets”保存到原來的 excel 文件中,同樣用選項 @t 指明首行記錄爲標題。

 

這段腳本只有三句話,短小精幹之餘,邏輯清晰,也比較容易理解。下面我們再看看如何合併多個文件中的多個工作表。

B.  不同 excel 中的多表合併

下面是要合併的多個 excel 文件,它們都具有和上面例子相同的表結構,每個文件記錄了當年的數據  


集算器 SPL 腳本:


A

B

1

for   directory@p(”d:/excel/*.xlsx“)

=file(A1).xlsopen()

2


=B1.conj(B1.xlsimport@t('Customer   Name','Sale Amount','Purchase Date';~.stname))

3


=@|B2

4

>   file(“d:/result.xlsx”). xlsexport@t(B3;"merge_data")


合併的效果如下:

Customer Name

Sale Amount

Purchase Date

John Smith

1200

2013-01-01

Mary Harrison

1425

2013-01-06

Lucy Gomez

1390

2013-01-11

Rupert Jones

1257

2013-01-18

......

......

......

Thomas Haines

1346

2013-02-17

 腳本說明:

A1:通過 for 循環,遍歷指定目錄下的 excel 文件,在 B1 到 B3 之間進行循環內處理.

B1:打開目錄下的一個 excel 文件,生成序列。

B2:導入當前文件中的每個 sheet 工作表中指定列'Customer Name','Sale Amount','Purchase Date'的數據,然後合併這些數據,與前面例子中的 A2 類似。

B3:將序表 B2 的數據與 @表示的本網格的值進行合併。

A4:將序表 B3 保存到result.xlsx文件中的 merge_data 工作表中。


上面程序用兩個循環就實現了多個 excel 文件數據合併,外循環 for 遍歷了目錄下所有的 excel 文件,內循環B1.conj則合併每個excel文件中的多個sheet工作表的數據。

C.  合併出大文件

前面第一個例子中的 A2、第二個例子中的 B3 都是在內存中裝載了合併後的 Excel 的所有數據,然後一次性寫出。如果文件太多太大,那麼對內存的佔用也會很大,甚至超出內存允許的範圍。爲此,我們可以採用流式追加的方式生成大文件。

 

集算器 SPL 腳本:


A

B

1

=file("D:/out.xlsx")


2

for   directory@p(”d:/excel/*.xlsx“)

=file(A2).xlsopen()

3


=if(A1.exists(),B2.xlsimport@t(),B2.xlsimport())

4


>A1.xlsexport@s(B3;"merger")


合併後的效果如下:

Customer ID

Customer Name

Invoice Number

Sale Amount

Purchase Date

1234

John Smith

100-0002

1200

2013-01-01

2345

Mary Harrison

100-0003

1425

2013-01-06

3456

Lucy Gomez

100-0004

1390

2013-01-11

4567

Rupert Jones

100-0005

1257

2013-01-18

......

......

......

......

......

6789

Thomas Haines

100-0002

1346

2013-02-17

 

腳本說明:

A1:打開指定輸出的文件。
A2: 遍歷目錄下需要合併的 excel 文件。

B2:打開一個需要合併的 excel 文件。

B3:如果輸出文件不存在,讀取 sheet 工作表的所有數據,包括標題行;如果輸出文件已經有了,就通過 @t 選項指明第一行是標題,從第二行開始讀取數據。

B4:將 B3 讀取的數據以流式追加到 A1 指定的輸出文件的 merger 工作表中。


      通過流式逐個讀取文件數據後追加寫入,這個方式適合將大量小的 excel 文件合併成一個大的 excel 文件。

3.  分組彙總

下面繼續以前面的銷售數據 excel 文件爲例。

A.  字段分組

根據某個字段或多個字段實現分組計算,腳本如下:


A

B

1

=file(”D:/sales_2013.xlsx”).xlsopen()


2

=A1.conj(A1.xlsimport@t(;~.stname))


3

=A2.groups('Customer ID';sum('Sale   Amount'):Total,avg('Sale Amount'):Average)


4

=A2.groups('Customer ID','Purchase Date';sum('Sale   Amount'):Total)


 

A3的效果:

Customer   ID

Total

Average

1234

2550

1275.0

2345

3214

1607.0

3456

2901

1450.5

4321

4132

2066.0

……

……

……

4567

1257

1257.0

 A4的效果:

Customer ID

Purchase Date

Total

1234

2013-01-01

1200

1234

2013-03-04

1350

2345

2013-01-11

1425

2345

2013-03-17

1789

……

……

……

9876

2013-02-02

1115

 腳本說明:

A1:打開指定的 excel 文件。

A2:讀取併合並文件中所有 sheet 工作表的數據。

A3:在合併後的數據上按字段 'Customer ID' 分組求銷售額、平均值

A4:在合併後的數據上按字段 'Customer ID', 'Purchase Date' 分組求銷售額

B.  按序分組

集算器在進行分組聚合時還可以和相鄰數據行對比,在原數據已經有序時可以不再排序,從而節省時間,並保持原有的次序。假設原數據已經按日期排序,我們想按月份分組統計時,代碼如下。

集算器 SPL 腳本:


A

B

1

for directory@p(”d:/excel/*.xlsx“)

=file(A1).xlsopen()

2


=B1.conj(B1.xlsimport@t(;~.stname))

3


=@|B2

4

=B3.derive(year('Purchase Date'):Year,month('Purchase   Date'):Month)


5

=A4.groups (month('Purchase Date'):Month;sum('Sale   Amount'):Total,avg('Sale Amount'):Average)


6

=A4.groups@o (month('Purchase Date'):Month;sum('Sale   Amount'):Total,avg('Sale Amount'):Average)


 

A5分組效果:

Month

Total

Average

1

272414

15134.111111111111

2

168038

9335.444444444445

3

357693

19871.833333333332

A6分組效果:

Month

Total

Average

1

8992

1498.6666666666667

2

9375

1562.5

3

10139

1689.8333333333333

1

260221

43370.166666666664

2

103656

17276.0

3

101509

16918.166666666668

1

3201

533.5

2

55007

9167.833333333334

3

246045

41007.5

 

腳本說明:

A1至 B3:在前面的例子中已經介紹,將同一目錄下所有相同結構的 excel 文件的工作表進行合併。

A4:在序表 B3 的基本上重新構造了一個序表 A4,將日期拆分,新增年、月字段。

A5:groups 跨年度按月分組彙總銷售額、平均值。

A6:groups@o 按年月分組彙總銷售額、平均值, 帶參數 @o 實現分組歸併處理.

 

其中,A4 爲數據記錄明細;A5 按月統計, 不區分年;A6 則按年月統計。這三個單元格中的數據展現出了不同層次的合併彙總結果。

C.  分段分組

將要統計的數據按條件分成幾段,統計各組的情況。

集算器 SPL 腳本:


A

B

1

for   directory@p(”d:/excel/*.xlsx“)

=file(A1).xlsopen()

2


=B1.conj(B1.xlsimport@t(;~.stname))

3


=@|B2

4

=B3.groups(if   ('Sale Amount'<1000,"1::<1000",

if   ('Sale Amount'<1500,"2::1000~~1500",

if   ('Sale Amount'<2000,"3::1500~~2000",

if   ('Sale Amount'<2500,"4::2000~~2500",

"5::>=2500")))):Segment;

count(1):Number,sum('Sale   Amount'):Total)



分組效果:

Segment

Number

Total

1::<1000

22

8280

2::1000~~1500

9

11617

3::1500~~2000

6

10432

4::2000~~2500

4

8810

5::>=2500

13

759006


代碼說明:

步驟A1到 B3 之間參考前面例子的說明。

A4:字段'Sale Amount'金額的範圍分成 5 段,然後累計求出各段的數量及總數。


不過,這樣的寫法不夠方便,如果我們想調整分段方案,就需要修改 groups 函數的參數,而這個參數表達式還是比較複雜的。這時,我們還可以利用集算器中另一個 pseg 函數,更方便地實現這個功能,腳本如下:


A

B

1

[0,1000,1500,2000,2500]


2

for directory@p(”d:/excel/*.xlsx“)

=file(A1).xlsopen()

3


=B1.conj(B1.xlsimport@t(;~.stname))

4


=@|B2


=B4.groups(A1.pseg(~.'Sale   Amount'):Segment;

count(1):Number,sum('Sale Amount'):Total)


 

當然,我們也可以根據需要,按不同字段不同要求進行分組,然後進行統計處理。例如,在統計班級考生成績時,各科成績可劃分成優、良、中、差、及格的分數區段,一次爲條件進行統計。groups 用法還有很多,可以參考函數手冊中相應的章節。

D.  大數據分組

前面的例子中,要讀取的 excel 文件都不能很大,也就是都能一次讀進內存。手工處理大文件,也會有類似的要求,因爲同時打開多個文件,意味着把這些文件都裝入內存,很可能會超過機器的物理內存,而用 VBA 讀取的情況也差不多。這時,我們就需要用流式的方法讀取數據,不需一次讀進內存,而是邊讀取邊合併。

 

集算器 SPL 腳本:


A

B

1

=file(“d:/tdata.xlsx”).xlsopen@r()


2

for   A1.count()

=A1.xlsimport@ct(;A1(A2). stname)

3


=@|B2

4

= B3.conjx()

=A4.groups('Customer   ID';sum('Sale Amount'):SaleTotal)


>file(“d:/out.xlsx”).exportxls@bt(B4;"Customer&Sales")


  

篩選分組的效果:

Customer ID

SaleTotal

1234

107721792

2345

139041639

3456

137985543

4321

96170742

...

...

9876

37590417

 

代碼說明:

A1:使用 @r 選項指明以流式打開 excel 文件。
A2:遍歷 excel 中的 sheet 工作表。

B2:使用 @c 選項指明以遊標方式導入數據。

B3:將遊標B2彙集到B3序列中。

A4:將遊標序列B3的成員合併到一起組成新的遊標。

B4: 序列A4按‘Customer ID’分組累計‘Sale Amount’。

A5:將結果保存。

 

通過遊標以流的方式循環從大文件中讀取一段段數據,實現對數據的分組合並。

4.  去重處理

實際數據合併過程中,往往會出現數據重複的現象,重複數據肯定會影響到我們對數據的計算分析。下面介紹使用集算器 SPL 腳本去除重複數據的幾種主要解決方法。

A.  主鍵去重

sales_2013中的數據,設其主鍵爲’Invoice Number’,則根據主鍵去掉重複記錄。


A

B

1

=file(“d:/sales_2013.xlsx”).xlsopen()


2

=A1.conj(A1.xlsimport@t('Customer   Name', 'Invoice Number', 'Sale Amount';~. stname))


3

=A2.group@1('Invoice   Number')


4

>file(“d:/out.xlsx”).   xlsexport@t(A3;"result")


 

合併去重後的數據:

Customer Name

Invoice Number

Sale Amount

John Smith

100-0002

1200

Mary Harrison

100-0003

1425

Lucy Gomez

100-0004

1390

Rupert Jones

100-0005

1257

Jenny Walters

100-0006

1725

……

……

……

Susan Wallace

100-0019

2280

 

代碼說明:

A1:打開指定的 excel 文件。

A2:導入 sheet 工作表中指定列的數據。

A3:將序表 A2 按主鍵' Invoice Number '分組去重處理, 其中參數 @1 表示取每一個分組的第一條記錄組成排列後返回(注意是數字 1,不是字母 l)。

A4:將結果保存。

各個 sheet> 中的數據是唯一的,但合併的數據不一定是唯一的,因此採用主鍵方式去掉重複數據。

B.  某字段去重

根據數據表sales_2013中的某字段去重處理, 查看不同姓名的僱員記錄.


A

B

1

=file(“d:/sales_2013.xlsx”).xlsopen()


2

=A1.conj(A1.xlsimport@t('Customer   ID', 'Customer Name';~. stname))


3

=A2.id('Customer   Name')


4

=A2.group@1('  Customer Name')


5

>file(“d:/out.xlsx”).   xlsexport@t(A4;"result")


代碼說明:

A1:打開指定的 excel 文件。

A2:導入 sheet 工作表中指定列的數據。

A3: 從序表 A2 中獲取不重複姓名的記錄

A4:從序表 A2中獲取不重複姓名的記錄列表。

A5:將序表 A4 另存,首行記錄爲標題。

 

A3數據去重結果:

Member

Anushka Vaz

Daniel Farber

Harriet Cooper

……

Tony Song

A4數據去重結果:

Customer ID

Customer Name

5432

Anushka Vaz

9876

Daniel Farber

4321

Harriet Cooper

……

……

8765

Tony Song 

C.  聯合多字段去重

有的記錄雖然有主鍵,但判斷是否爲重複的記錄,需要用其它幾個字段來確定,此時用多個字段聯合來確定是否有重複記錄.


A

B

1

=file(“d:/sales_2013.xlsx”).importxls@t()


2

=file(“d:/sales_2014.xlsx”).importxls@t()


3

=[A1,A2].merge('Customer   ID', 'Purchase Date')


4

=A3.group@1('Customer   ID', 'Purchase Date')


5

>file(“d:/out.xlsx”).   xlsexport@t(A4;"result")


 

代碼說明:

A1:導入指定 excel 文件的數據。

A2:同上。

A3:按字段 'Customer ID', 'Purchase Date' 合併序表 A1,A2,返回序表 A3

A4:序表 A3 按 'Customer ID', 'Purchase Date' 分組去重。

A5:將結果保存。
當然,也可以根據需要,參考更多的字段進行分組合並,去掉重複記錄。

D.  記錄級去重

   解決要合併的每個文件中的記錄本身是不重複的,但合併後可能存在重複記錄。


A

B

1

=file(“d:/sales_2013.xlsx”).importxls@t()

=A1.group@1('Invoice   Number')

2

=file(“d:/sales_2014.xlsx”).importxls@t()

=A2.group@1('Invoice   Number')

3

=[B1,B2].merge@u()

=A3.count()

代碼說明:

A1:導入 excel 文件的數據。

B1: 根據字段'Invoice Number'去掉序表 A1中的重複數據

A2、B2:同上。

A3:合併序表 B1,B2 的數據,並去掉重複數據記錄返回序表 A3。選項 @u 表示序表成員按順序合併到一起組成新的序表, 去掉重複的記錄。

B3: 查看合併後的數據記錄數。
merge@u適合對多序表合併處理, 其中序表內部有序且無重複數據。

 

本文主要介紹了集算器處理同構 excel 多文件合併、分組彙總數據及數據去重幾種情況,在實際工作中,還會遇到異構的情況,只要把需要合併的字段讀成集算器的集合對象,後續處理和同構的邏輯是一樣的。學會了用這種專業數據處理工具,不僅能合併 Excel 文件, 合併其他文本數據方法也是一致的,再也不用擔心合併數據中的多文件、大文件和結構差異問題了。


5.  附件:

salesrar


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