<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    大大毛 的筆記

      DDM's Note

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

    posts - 14, comments - 23, trackbacks - 0, articles - 58
       :: 首頁 ::  :: 聯系 ::  :: 管理

    複雜SQL語句的構建以及內部的封裝調試

    Posted on 2007-01-02 08:54 大大毛 閱讀(675) 評論(0)  編輯  收藏 所屬分類: SQL

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

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

    ?????????再來說說環境的事情,開發環境是用VB的DLL實現功能封裝,因此我的報表會是一個cls,ASP頁面只要實現View即可。數據環境是用MSSQL2000,第1個難點出現在這裡:數據環境雖說是用的MSSQL,但是卻不能使用Procedure;DB的設計也增加了難度:整個DB實現上是包含了兩個系統的數據庫,不同的結構,不同的命名規則,卻有相同含義的字段。為了便於說明,拉一個示例數據庫出來先:

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

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

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

    ??????約束
    ?????????不允許使用存儲過程,只能在VB的DLL中實現。

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

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

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

    CODE

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

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

    i am ddm

    主站蜘蛛池模板: 久久夜色精品国产噜噜亚洲a| 亚洲免费福利在线视频| 在线观看日本免费a∨视频| 国产精品免费久久久久影院| 亚洲一区二区三区播放在线| 四虎成人免费网站在线| 99久久免费看国产精品| 在线看片免费人成视频久网下载| 久久亚洲中文字幕精品有坂深雪| 国产乱码免费卡1卡二卡3卡| 特黄aa级毛片免费视频播放| 亚洲一级特黄特黄的大片| 久久久久久亚洲Av无码精品专口| 精品国产免费一区二区| 国产日韩AV免费无码一区二区| 亚洲成aⅴ人片在线观| 亚洲AV无码久久精品成人| 手机在线免费视频| 亚洲视频免费在线播放| 无码日韩精品一区二区三区免费 | 国产亚洲人成A在线V网站| 国产精品国产自线拍免费软件| 中国性猛交xxxxx免费看| 日韩在线一区二区三区免费视频| 久久久久亚洲av无码专区| 亚洲国产精品成人精品无码区在线| 亚洲黄色免费网址| 亚洲精品第一国产综合亚AV| 亚洲AV无码久久精品成人| 亚洲国产精品无码专区影院 | 免费少妇a级毛片人成网| 日本黄页网站免费| 午夜时刻免费入口| 国产国产人免费人成免费视频 | 日日夜夜精品免费视频| 一级毛片aaaaaa免费看| 日本免费电影一区二区| 97无码人妻福利免费公开在线视频 | 亚欧乱色国产精品免费视频| eeuss在线兵区免费观看| 久久er国产精品免费观看8|