大大毛 的筆記

            DDM's Note

          哪怕沒有辦法一定有說法,
          就算沒有鴿子一定有烏鴉,
          固執(zhí)無罪 夢想有價,
          讓他們驚訝.

          posts - 14, comments - 23, trackbacks - 0, articles - 58
             :: 首頁 ::  :: 聯(lián)系 ::  :: 管理

          ???前言
          ??????這段時間還一直在努力之中,這一次在SQL的構(gòu)建上遇到一個挑戰(zhàn),不過這一次的挑戰(zhàn)是自找的

          ??????開發(fā)環(huán)境是VB6的DLL+ASP,分到的活是一個報表模塊。
          ??????需求
          ?????????我這一塊的報表,現(xiàn)階段是要實(shí)現(xiàn)兩個功能(就我看應(yīng)該只是一個,需求理解錯誤可不是我的事兒),為了與其它的模塊保持一致,工作流程如下:
          ?????????1.輸入查詢的年 / 月;
          ?????????2.查詢結(jié)果並以網(wǎng)頁表格的方式提供預(yù)覽;
          ?????????3.選擇發(fā)送郵件功能;
          ?????????4.選取需要發(fā)送的郵件收件人列表;
          ?????????5.查詢結(jié)果生成Excel文件並以郵件附件的方式發(fā)送。
          ??????
          輸入
          ?????????參數(shù)是一個 年份值+月份值:
          ?????????1. lngYear (0001-9999),年份值;
          ?????????2. lngMonth (1-12),月份值.
          ?????????由於Input參數(shù)少,JS檢驗比較簡單,因此會在客戶端JS提供第一層的校驗,而模塊裡面就不再做檢驗,捕獲異常即可。
          ??????輸出
          ?????????根據(jù)輸入的參數(shù),搜尋記錄,提供瀏覽以及發(fā)送Excel報表的能力(以郵件附件的方式發(fā)送,在此不做論術(shù))。

          ?????????再來說說環(huán)境的事情,開發(fā)環(huán)境是用VB的DLL實(shí)現(xiàn)功能封裝,因此我的報表會是一個cls,ASP頁面只要實(shí)現(xiàn)View即可。數(shù)據(jù)環(huán)境是用MSSQL2000,第1個難點(diǎn)出現(xiàn)在這裡:數(shù)據(jù)環(huán)境雖說是用的MSSQL,但是卻不能使用Procedure;DB的設(shè)計也增加了難度:整個DB實(shí)現(xiàn)上是包含了兩個系統(tǒng)的數(shù)據(jù)庫,不同的結(jié)構(gòu),不同的命名規(guī)則,卻有相同含義的字段。為了便於說明,拉一個示例數(shù)據(jù)庫出來先:

          ?????????
          PDM (去掉全部無關(guān)字段)

          ?????????可以看到,DB中以 tbXXX 方式命名的表與 XXX(AS400) 的表有著很大的差異,但是它們之間又存在著相同之處。
          ??????再來看看表間的隱式關(guān)聯(lián)關(guān)係 (沒有以FK的方式加以約束)

          • 合約租金(tbContractRent)? 與 職場(tbPlace)的關(guān)聯(lián):職場代碼相同 ,合約是職場在某一段時間的表現(xiàn),即相同職場在某一時刻只會存在一份合約
          • 合約租金(tbContractRent)? 與 職場單位(tbUnit)的關(guān)聯(lián):單位的坪數(shù)生效日/坪數(shù)失效日的區(qū)間 落在一份合約租金生效/租金失效區(qū)間之內(nèi)
          • 職場單位(tbUnit) 與 單位資料AS400(AAABREP)的關(guān)聯(lián):單位代碼 + 單位序號 相同
          • 職場單位(tbUnit) 與 單位資料2AS400(DAD6CPP)的關(guān)聯(lián):(單位代碼 + 單位序號 相同) 並且 (原職場代碼 = 職場代碼 或 新職場代碼 = 職場代碼)
          • 合約租金(tbContractRent)? 與 職場資料AS400(DAC9CPP)的關(guān)聯(lián):職場資料到期日?落在 一份合約租金生效/租金失效日區(qū)間之內(nèi)
          ???????功能描述
          1. “閒置租約”:
            職場單位與租約相關(guān),這裡的“閒置”狀態(tài)由單位引發(fā),描述是指在一份合約內(nèi),單位發(fā)生過“撤銷”,然後就會從職場中“遷出”,那麼遷出日期--合約租金失效日的區(qū)間內(nèi)即是“閒置”。
            因此該功能的條件入口表是 合約租金(tbContractRent),該功能的業(yè)務(wù)邏輯比較複雜,流程如下:
            a. 在考察期內(nèi)有效的合約;
            b. 在合約中的單位發(fā)生過“撤銷”-- 通過(tbUnit)連接到(AAABREP)檢查是否存在有撤銷日期(合法日期 並且 發(fā)生在考察期之前),另外由於存在業(yè)務(wù)邏輯,這裡的撤銷日期在使用時需要向後加一個月;
            c. 如果該單位符合撤銷條件則通過(tbUnit)連接到(DAD6CPP)獲取搬遷日期,同樣的,這裡所得到的搬遷日期由於一定的業(yè)務(wù)邏輯,還需要檢查它的有效性,只有大於撤銷日期的才會認(rèn)定為是合法的搬遷日期,否則將使用(tbUnit)表中的坪數(shù)失效日來做為該單位的搬遷日期;
            d. 搬遷日期必須早於考察的結(jié)束時間;
          2. “待退職場”:
            是指一個職場的最後一份合約的失效日落在考察期內(nèi),由於相同資料的以 XXXAS400表為主,因此條件入口表是職場資料AS400(DAC9CPP)
          3. 最終的表現(xiàn)形式是一張2維表格的方式,即功能1 與 功能2的結(jié)果要放在一起

          ??????約束
          ?????????不允許使用存儲過程,只能在VB的DLL中實(shí)現(xiàn)。

          ??????思考及方案選擇
          ?????????1. 功能1是這次任務(wù)的難點(diǎn),實(shí)現(xiàn)邏輯需要跑的表比較多,而且邏輯間也比較複雜,看上去並不能簡單的用 Inner/Left Join + Where就可以搞定那幾表。
          ?????????2. 最終的結(jié)果集會建立在指定的幾張表上,與實(shí)現(xiàn) 功能 所聯(lián)接的表並不相同,無法在結(jié)果表上進(jìn)行直接篩選,還需要將上面所拿到的條件結(jié)果集與最終的表現(xiàn)表進(jìn)行一次關(guān)聯(lián)。
          ?????????3. 實(shí)現(xiàn)這次功能的方法有兩種:
          ?????????3.1. 用ADO對象的嵌套來實(shí)現(xiàn),配合上帶層次的 Function ,這是比較傳統(tǒng)的解決方案,完全可以解決這類問題。
          ????????????優(yōu)點(diǎn)
          ????????????a. 適用面廣,複雜度比較低;
          ????????????b. 函數(shù)封裝,功能邏輯清晰;
          ????????????缺點(diǎn)
          ????????????a.?很明顯的,在這次的任務(wù)中要實(shí)現(xiàn)功能,需要使用3層以上的循環(huán),這種邊循環(huán)邊查詢的方式的效率是極低的;
          ?????????3.2. 嚐試使用複雜SQL來構(gòu)造邏輯實(shí)現(xiàn)。
          ????????????使用這種解決方法,在該問題上算是一種比較酷的解決。使用它的好處就是能提高查詢效率,當(dāng)然對於我來說,這算是一種嚐試和創(chuàng)新,嘻嘻。
          ????????????優(yōu)點(diǎn)
          ????????????a. 查詢效率高,因為它只會發(fā)出一條SQL;
          ????????????缺點(diǎn)
          ????????????a. 難於構(gòu)建,複雜度高;
          ????????????b. 如果結(jié)構(gòu)不好則很難調(diào)試及更改,發(fā)生需求變更時改動難度大;

          ??????細(xì)節(jié)分析
          ?????????最終俺決定使用複雜SQL來構(gòu)建邏輯,雖說實(shí)現(xiàn)起來會很困難,時間也蠻緊巴的,不過這是一個挑戰(zhàn),我之前也對自己的能力抱有信心。好了,切入正題,談?wù)勎业膶?shí)現(xiàn)細(xì)節(jié)。
          ?????????對於之前所考慮到的問題,我針對性的設(shè)計一種結(jié)構(gòu)來應(yīng)付它。
          ?????????a. 由於這次的查詢條件表比較多,各表間無法直連,所以我在表這一層上使用封裝,以降低它們之間的瓜葛,並試圖將表這一層的變動壓抑在封裝之內(nèi),這一點(diǎn)至關(guān)重要,因為SQL就象是一座塔,底部會由幾個基礎(chǔ)表支撐,這就好比萬噸壓力全都壓在幾個支撐柱上,一旦柱子垮了塔也將不復(fù)存在;
          ?????????b. 在 a 的表封裝基礎(chǔ)上使用模塊化的構(gòu)建,SQL語句說到底都是一句句拼湊起來的,再複雜的語句也不過如此。因此按照邏輯一步步的走下來,逐步的封成單一的模塊,最後再象積木一樣搭建起來是很重要的;
          ?????????c. 這次頁面的功能是有分成 2 個部分的,而這2功能的查詢?nèi)肟诒砑斑B接順序又不相同(不要跟我說表 A 連接到 表 B 與表 B 連接到表 A 的邏輯是相同的),不過邏輯的核心表都落在合約租金(tbContractRent)?上,因此采取將產(chǎn)出表與條件表切割開來,而2功能使用聯(lián)合的辦法來完成產(chǎn)出與邏輯的分離,SQL的結(jié)構(gòu)示例成為這樣: Select * From 產(chǎn)出表 Join (功能1 Union 功能2) As 功能表?On 產(chǎn)出與邏輯間的關(guān)聯(lián)。
          ?????????d. 對於SQL的調(diào)試問題,由於成品SQL的體積會使得調(diào)試起來頗為複雜,因此我在功能模塊上增加調(diào)試用的接口,這樣就能夠?qū)⒅鸩叫纬傻陌氤善方o輸出來,有利於外步調(diào)試時的分步分析;
          ?????????e. 為便於SQL調(diào)試,在代碼的書寫上使用了一點(diǎn)小技巧。通常在合成SQL時語句的寫法會是這樣:
          ?????????strSQL="Select * From Table Where col1='" & p1 & "' And col2='" & p2 & "'"
          ?????????這樣的寫法會增加源代碼的檢查難度,大量的字符串連接符和變量充斥其中,現(xiàn)在改成這樣寫:
          ?????????strSQL = "Select * From Table Where col1=@p1 And col2=@p2"
          ?????????在 SQL 語句搭建完成後再使用 strSQL = Repalce(strSQL,"@p1","'xxx'") 的方式來代入?yún)?shù),即不會影響使用,又降低了源碼的檢查難度,而且配合調(diào)試時輸出:
          ?????????declare @p1 char(8),@p2 char(8)
          ?????????select @p1='xxx',@p2='yyy'
          ?????????這樣一來,就可以很方便地將調(diào)試 SQL 語句直接 Copy 進(jìn)查詢分析器,直接修改輸入?yún)?shù)進(jìn)行調(diào)試分析了。

          ??????實(shí)現(xiàn)代碼
          ?????????第一次嚐試使用這種方法來實(shí)現(xiàn),花了很長時間(約2天時間)才完成,還好調(diào)試時只遇到了一個很小的失誤,以後模塊又經(jīng)歷了多次變更,後續(xù)文章中會加以討論在這種實(shí)現(xiàn)方式下我是如何跟隨需求變更的,當(dāng)然,經(jīng)過了N次的變更之後,還是....

          CODE

          ??????看這段代碼需要的是耐心,順著邏輯一步步地往下走才行。
          ??????代碼中對基礎(chǔ)表的封裝,可以看 str[表名]_TB 這樣命名的變量,它將一張表封裝起來,然後重要的一點(diǎn)就是逐層的表命名,這裡使用了原表的名稱,雖然看起來有些混亂,但是這是調(diào)試所必需的。
          ?

          ??????後記
          ?????????這一次的嚐試,在時間上消耗比較大,開始時對於結(jié)果的正確性還有著一絲懷疑,不過在完工後也就釋然了,只有一處比較小的筆誤進(jìn)行過調(diào)試,算是對這次的結(jié)構(gòu)上的一點(diǎn)肯定吧,嘻嘻。
          ?????????哎,不過測試時還是遇到了令人沮喪的事情,這次測試MM最終對我說任務(wù)很忙,俺的測試報告自己寫就好,咳咳。
          ?????????如果有仔細(xì)看完上面的SQL源碼,不難看出除了在結(jié)構(gòu)上完成了表及表間邏輯的封裝外,而且將最終形成的視圖邏輯也進(jìn)行了封裝,因此在ASP視圖中僅僅需要完成循環(huán)顯示即可,這除了簡化ASP視圖外,還對後面幾次的需求變動造成了很深的影響,決定了日後變動的走向。

          i am ddm

          主站蜘蛛池模板: 宝鸡市| 马鞍山市| 襄垣县| 米泉市| 东光县| 织金县| 阳山县| 额济纳旗| 楚雄市| 环江| 旅游| 吕梁市| 福建省| 左贡县| 高碑店市| 桐柏县| 通山县| 雷州市| 义马市| 濮阳县| 金门县| 灯塔市| 彰武县| 隆林| 理塘县| 南汇区| 鄂温| 北碚区| 新巴尔虎左旗| 东方市| 神池县| 云南省| 武平县| 武胜县| 齐河县| 永昌县| 晋中市| 泰兴市| 巴中市| 和田市| 维西|