差異數(shù)據(jù)的對比和整理
在我們?nèi)粘5墓ぷ髦?,常常?huì)遇到很多結(jié)構(gòu)相同,但來源不同的數(shù)據(jù)。有時(shí),這些數(shù)據(jù)之間完全獨(dú)立,互不重疊,例如各個(gè)分公司從自己系統(tǒng)中導(dǎo)出的銷售數(shù)據(jù);但有時(shí),這些數(shù)據(jù)之間又會(huì)有大量的重疊,例如常見的一個(gè)完整業(yè)務(wù)流程中涉及的各個(gè)系統(tǒng)、各個(gè)環(huán)節(jié),都可能根據(jù)各自收到的單據(jù)進(jìn)行錄入。這時(shí),如何對這些重疊數(shù)據(jù)進(jìn)行對比,從而發(fā)現(xiàn)和糾正其中的錯(cuò)誤,就需要我們常說的“自動(dòng)對賬”操作了。
在一般業(yè)務(wù)系統(tǒng)的設(shè)計(jì)開發(fā)中,這種對賬功能的邏輯基本上都是通過循環(huán)遍歷一套數(shù)據(jù)的記錄,在另一套記錄數(shù)據(jù)中逐一比對查找。雖然代碼邏輯高度類似,但又常常因?yàn)楸葘λ藐P(guān)鍵字的差異,以及可能發(fā)生的需求變化而需要單獨(dú)編寫,最終導(dǎo)致開發(fā)成本居高不下,維護(hù)難度越來越大。
現(xiàn)在有了集算器,類似問題的處理,就會(huì)變得直觀而且便捷,因?yàn)榧闫髦刑峁┝苏嬲嫦蚣系母鞣N運(yùn)算。具體到差異數(shù)據(jù)的對比和整理,只需要sort()和merge()兩個(gè)函數(shù)既可以了。
我們以一個(gè)簡化了的銷售記錄合并的例子來進(jìn)行說明。
下表顯示的兩個(gè)文件old.csv和new.csv分別代表預(yù)計(jì)銷售的情況和實(shí)際銷售的情況,都包含了銷售人員姓名userName、銷售日期date、銷售額saleValue、銷售數(shù)量saleCount。在業(yè)務(wù)分析時(shí),需要分別找出新增的、刪除的、修改的數(shù)據(jù)行進(jìn)行分析,其中userName和date作為進(jìn)行比對的關(guān)鍵字,也稱為邏輯主鍵:
Old.csv | New.csv | |
. 1 2 3 4 5 6 7 8 9 |
userName,date,saleValue,saleCount Rachel,2015-03-01,4500,9 Rachel,2015-03-03,8700,4 Tom,2015-03-02,3000,8 Tom,2015-03-03,5000,7 Tom,2015-03-04,6000,12 John,2015-03-02,4000,3 John,2015-03-02,4300,9 John,2015-03-04,4800,4 . |
userName,date,saleValue,saleCount Rachel,2015-03-01,4500,9 Rachel,2015-03-02,5000,5 Ashley,2015-03-01,6000,5 Rachel,2015-03-03,11700,4 Tom,2015-03-03,5000,7 Tom,2015-03-04,6000,12 John,2015-03-02,4000,3 John,2015-03-02,4300,9 John,2015-03-04,4800,4 |
可以看到new.csv中的第2、3行是新增的記錄,可能對應(yīng)額外成交的新訂單,第4行是修改的記錄,可能對應(yīng)成交價(jià)格變化,old.csv中第3行是刪除的記錄,可能對應(yīng)撤銷的訂單。
傳統(tǒng)邏輯的比對代碼我們不再贅述,直接看一看在集算器中是如何處理的:
A | B | |
1 | =file(“d:\\old.csv”).import@t(;”,”) | =file(“d:\\new.csv”).import@t(;”,”) |
2 | =A1.sort(userName,date) | =B1.sort(userName,date) |
3 | =new=[B2,A2].merge@d(userName,date) | |
4 | =detete=[A2,B2].merge@d(userName,date) | |
5 | =diff=[B2,A2].merge@d(userName,date,saleValue,saleCount) | |
6 | =update=[diff,new].merge@d(userName,date) | result update |
沒錯(cuò),就這么幾行,沒有循環(huán)遍歷,沒有查詢算法優(yōu)化,而且如果比對的關(guān)鍵字變化了,只需要修改這么一目了然的幾行。讓我們從上到下捋一下:
A1,B1:以逗號(hào)為分隔符讀入文件,形成兩個(gè)原始的數(shù)據(jù)集合。這里也可以從其他格式的文件或數(shù)據(jù)庫的數(shù)據(jù)表中讀取。
A2,B2:使用sort()函數(shù),將數(shù)據(jù)按照關(guān)鍵字,也就是邏輯主鍵排序,形成新的集合。以便后面的merge()函數(shù)使用。
A3:查找新增記錄,也就是關(guān)鍵字userName和date在集合B2中同時(shí)不在集合A2中,這就是集合的“差集”計(jì)算,是通過函數(shù)選項(xiàng)@d指定的,類似的還有并集@u,交集@i。計(jì)算得到一個(gè)新的集合“new”如下:
A4:這次查找被刪除的記錄,也就是關(guān)鍵字userName和date在集合A2中但不在B2中的記錄,注意merger()函數(shù)前方括號(hào)中A2、B2的次序不同。同樣計(jì)算得到一個(gè)新的集合“delete”結(jié)果如下:
A5:和A3一樣,查找B2與A2的差集,但這次將所有字段都作為關(guān)鍵字,因此會(huì)找到所有變化的記錄,包括修改過的和新增的記錄。這個(gè)結(jié)果形成的新集合“diff”如下:
A6:很明顯“diff”集合中去掉新增的記錄,也就“new”集合,就是被修改過的記錄,對應(yīng)的集合“update”如下:
可以看到,在集合的概念下,記錄的新增、刪除、修改都有著直觀的含義,無非就是新、老集合的不同部分,通過相應(yīng)的集合運(yùn)算可以非常方便的表示。
這樣計(jì)算得到的結(jié)果,除了可以在計(jì)算的IDE中查看,或者通過文件處理函數(shù)輸出到文件中,還可以通過JDBC方式返回給 Java 程序或其他報(bào)表工具,代碼中的 B6 就顯示如何將這種對賬處理的結(jié)果非常簡單作為結(jié)果集返回給其他系統(tǒng)模塊,下面是Java程序中使用這個(gè)結(jié)果集的示例:
- //建立esProc jdbc連接
- Class.forName(“com.esproc.jdbc.InternalDriver”);
- con= DriverManager.getConnection(“jdbc:esproc:local://”);
- //調(diào)用esProc,其中test是腳本文件名,可接收參數(shù)
- st =(com.esproc.jdbc.InternalCStatement)con.prepareCall(“call test()”);
- st.execute();//執(zhí)行esProc存儲(chǔ)過程
- ResultSet set = st.getResultSet();//獲得計(jì)算結(jié)果
可以看到,集算器處理差異數(shù)據(jù),真正體現(xiàn)和“差異”的本質(zhì)含義,也就是集合的差異。事實(shí)上,這種差異數(shù)據(jù)廣泛存在與各種系統(tǒng)之中和不同系統(tǒng)之間,大到銀行、運(yùn)營商系統(tǒng)中的賬目數(shù)據(jù),小到個(gè)人文件系統(tǒng)中的查重和版本比較,只要明確了需要對比的數(shù)據(jù)集合和關(guān)鍵字,就可以靈活地通過集合運(yùn)算進(jìn)行各種整理工作了。