课程设计:基于SQL Server的银行ATM 存取款机系统设计与实现
目錄
- 前言
- 一、項目背景
- 1、項目任務(wù)
- 2、項目技能目標(biāo)
- 3、需求概述
- 4、開發(fā)環(huán)境
- 5 、問題分析
- (1) 銀行存取款業(yè)務(wù)介紹
- (2) 客戶信息
- (3) 銀行卡賬戶信息
- (4) 銀行卡交易信息
- (5) 銀行卡手工賬戶和存取款單據(jù)信息
- 二、項目實訓(xùn)內(nèi)容
- 1、實訓(xùn)一:制定《數(shù)據(jù)庫設(shè)計與編程規(guī)范》
- 2、實訓(xùn)二:數(shù)據(jù)庫分析設(shè)計與建模
- (1) 分析銀行 ATM 存取款系統(tǒng)實體
- (2) 規(guī)范數(shù)據(jù)庫結(jié)構(gòu)設(shè)計
- (3) 繪制 CDM 模型、生成 PDM 模型
- 3、實訓(xùn)三:創(chuàng)建數(shù)據(jù)庫
- (1) 創(chuàng)建數(shù)據(jù)庫
- (2) 創(chuàng)建各個數(shù)據(jù)表及相關(guān)的約束
- (3) 添加外鍵約束和生成數(shù)據(jù)庫關(guān)系圖
- 4、實訓(xùn)四:創(chuàng)建觸發(fā)器和插入測試數(shù)據(jù)
- (1) 創(chuàng)建級聯(lián)觸發(fā)器
- (2) 插入數(shù)據(jù)表的測試數(shù)據(jù)
- 5、實訓(xùn)五:模擬常規(guī)業(yè)務(wù)
- (1) 修改客戶密碼
- (2) 辦理銀行卡掛失
- (3) 統(tǒng)計銀行資金流通余額和盈利結(jié)算
- (4) 查詢本周開戶信息
- (5) 查詢本月單次交易金額最高的卡號和總交易金額最高的卡號
- (6) 查詢掛失客戶
- (7) 催款提醒業(yè)務(wù)
- 6、實訓(xùn)六:創(chuàng)建、使用視圖
- (1) 輸出銀行客戶記錄視圖VW_userInfo
- (2) 輸出銀行卡記錄視圖VW_CardInfo
- (3) 輸出銀行卡交易記錄視圖VW_TransInfo
- (4) 根據(jù)客戶登錄名查詢該客戶賬戶信息VW_OneUserInfo
- 7、實訓(xùn)七:存儲過程實現(xiàn)業(yè)務(wù)處理
- (1) 完成存款或取款業(yè)務(wù)
- (2) 產(chǎn)生隨機卡號
- (3) 完成開戶業(yè)務(wù)
- (4) 分頁顯示查詢交易數(shù)據(jù)
- (5) 統(tǒng)計未發(fā)生交易的賬戶
- 8、實訓(xùn)八:利用事務(wù)實現(xiàn)轉(zhuǎn)賬
| 加油加油 |
前言
? ? ? ? 本文章主要是在學(xué)了SQL Server后做的一個課程設(shè)計,全文有三萬多字,接近一千行,光簡簡單單寫這篇博客就花了不少時間,若有出現(xiàn)錯誤之處,請指出,定當(dāng)感激不盡,一起學(xué)習(xí),一起進(jìn)步。
一、項目背景
1、項目任務(wù)
- 使用PowerDesigner 完成數(shù)據(jù)庫設(shè)計
- 創(chuàng)建數(shù)據(jù)庫、創(chuàng)建表、創(chuàng)建約束
- 使用觸發(fā)器和插入測試數(shù)據(jù)
- 模擬常規(guī)業(yè)務(wù)、創(chuàng)建視圖
- 使用存儲過程實現(xiàn)業(yè)務(wù)處理
- 利用事務(wù)實現(xiàn)較復(fù)雜的數(shù)據(jù)更新
2、項目技能目標(biāo)
- 使用PowerDesigner 完成數(shù)據(jù)庫概念模型和數(shù)據(jù)庫物理模型設(shè)計。
- 使用 T-SQL 語句創(chuàng)建數(shù)據(jù)庫、表和各種約束。
- 使用 T-SQL 語句編程實現(xiàn)常見業(yè)務(wù)。
- 使用觸發(fā)器實現(xiàn)多表之間的級聯(lián)更新。
- 使用事務(wù)和存儲過程封裝業(yè)務(wù)邏輯。
- 使用視圖簡化復(fù)雜的數(shù)據(jù)查詢。
- 使用游標(biāo)技術(shù)實現(xiàn)結(jié)果集的行集操作。
3、需求概述
? ? ? ?某銀行是一家民辦的小型銀行企業(yè),現(xiàn)有十多萬客戶,公司將為該銀行開發(fā)一套 ATM 存取款機系統(tǒng),對銀行日常的存取款業(yè)務(wù)進(jìn)行計算機管理,以便保證數(shù)據(jù)的安 全性,提高工作效率。
? ? ? ?要求根據(jù)銀行存取款業(yè)務(wù)需求設(shè)計出符合第三范式的數(shù)據(jù)庫結(jié)構(gòu),使用 T-SQL 語言創(chuàng)建數(shù)據(jù)庫和表,并添加表約束,進(jìn)行數(shù)據(jù)的增刪改查,運用邏輯結(jié)構(gòu)語句、事 務(wù)、視圖和存儲過程,按照銀行的業(yè)務(wù)需求,實現(xiàn)各項銀行日常存款、取款和轉(zhuǎn)賬業(yè) 務(wù)。
4、開發(fā)環(huán)境
- 數(shù)據(jù)庫:SQL SERVER 2008 開發(fā)版
- 數(shù)據(jù)庫建模工具:PowerDesigner15
5 、問題分析
該項目的 ATM 存取款機業(yè)務(wù)如下:
(1) 銀行存取款業(yè)務(wù)介紹
? ? ? ?銀行為客戶提供了各種銀行存取款業(yè)務(wù)。詳見表 1
(2) 客戶信息
? ? ? ?每個客戶憑個人身份證在銀行可以開設(shè)多個銀行卡賬戶,開設(shè)賬戶時,客戶需要 提供的開戶數(shù)據(jù)如表 2 所示:
(3) 銀行卡賬戶信息
? ? ? ?銀行為每個賬戶提供一個銀行卡,每個銀行卡可以存入一種幣種的存款,銀行保 存賬戶如表 3 所示:
客戶持銀行卡在 ATM 機上輸入密碼,經(jīng)系統(tǒng)驗證身份后辦理存款、取款和轉(zhuǎn)賬 等銀行業(yè)務(wù)。銀行規(guī)定,每個賬戶當(dāng)前的存款金額不得小于 1 元。
(4) 銀行卡交易信息
? ? ? ?銀行在為客戶辦理業(yè)務(wù)時,需要記錄每一筆賬目,賬目交易信息如表 4 所示:
(5) 銀行卡手工賬戶和存取款單據(jù)信息
? ? ? ?該銀行要求這套軟件實現(xiàn)銀行客戶的開戶、存款、取款、轉(zhuǎn)賬和余額查詢等業(yè)務(wù),使得銀行儲蓄業(yè)務(wù)方便、快捷,同事保證銀行業(yè)務(wù)數(shù)據(jù)的安全性。
? ? ? ?為使開發(fā)人員盡快了解銀行業(yè)務(wù),該銀行提供了銀行卡手工賬戶和存取款單據(jù)的 樣本數(shù)據(jù),以供項目開發(fā)時參考,參加表 5 和表 6 。
二、項目實訓(xùn)內(nèi)容
1、實訓(xùn)一:制定《數(shù)據(jù)庫設(shè)計與編程規(guī)范》
- 長度規(guī)范:
? ? ? ?凡是需要命名的對象其標(biāo)識符均控制在 30 個字符以內(nèi),也即:SQL Server 中的 表名、字段名、函數(shù)名、存儲過程、觸發(fā)器、視圖等名字長度要盡量不超過 30 個字 符長度。 - 構(gòu)成規(guī)范:
? ? ? ?數(shù)據(jù)庫各種名稱必須以字母開頭,但嚴(yán)禁以系統(tǒng)關(guān)鍵字開頭,名稱只能含有字母、數(shù) 字以及下劃線“_ ”三類字符, “_ ”用于間隔名稱中的各語義字段;不要使用系統(tǒng)保留字作表名。 - 大小寫規(guī)范:
? ? ? ?構(gòu)成 SQL Server 數(shù)據(jù)庫中的各種名稱(表名、字段名、過程名、視圖名等所有命 名符的首字母需要使用大寫,也即每個命名單詞的首字母大寫,其它字符小寫。但對 于簡寫或縮寫的短單詞,如 ID 、UI 可以全為大寫。 - 主鍵規(guī)范:
? ? ? ?除臨時表、流水表以及日志表外,其它表都要建立主鍵。主鍵最好設(shè)計成單一主 鍵,盡量不要用復(fù)合主鍵,盡量使用沒有業(yè)務(wù)語義的字段作為主鍵,
如采用按順序自增的數(shù)值型字段為主鍵 - 注釋規(guī)范:
? ? ? ?每個表,每個字段都要有注釋,說明其含義,對于冗余字段還要特別說明其維護方法,外鍵字段要說明參照于那個表,另外對于存儲過程、視圖、觸發(fā)器、函數(shù)等代碼均要增加注釋,以保持代碼的可讀性以及后續(xù)的可維護性。 - 行大小規(guī)范:
? ? ? ?SQL Server 的 1 頁的大小是 8K,因此一行的數(shù)據(jù)要控制到 8K 之內(nèi),如果超過 8K 要想辦法將表進(jìn)行拆分成多個子表。 - 數(shù)據(jù)保留策略:
? ? ? ?大表由于數(shù)據(jù)量較大,往往是系統(tǒng)的性能瓶頸所在,因此對于大表的設(shè)計好考慮到今后的數(shù)據(jù)轉(zhuǎn)移、分片、Partition 等,并且對大表以及其相關(guān)表的數(shù)據(jù)保留時間也要有一個提前規(guī)劃,以免今后出現(xiàn)性能問題束手無策。 - 必備字段要求:
? ? ? ?每個大表都應(yīng)該添加以下幾個有用的字段,分別為創(chuàng)建日期、修改日期、操作人以及版本標(biāo)記,創(chuàng)建這些字段的目的是為今后的數(shù)據(jù)轉(zhuǎn)移以及分片或分區(qū)做準(zhǔn)備,同時也有利于今后的數(shù)據(jù)審計等。
注意事項:
? ? ? ?基于大表的任何操作都要慎重思考,通常情況下要禁止在大表上創(chuàng)建觸發(fā)器,禁止在大表上做頻繁的批量更新或刪除動作,禁止在生產(chǎn)時間對大表做 DDL 操作,禁止在大表上做全表掃描(Full Scan)等。 - 臨時表功能:
? ? ? ?SQL Server 分為全局臨時表和局部臨時表,臨時表在很多場合下能帶來意想不到 的效果,尤其是需要中轉(zhuǎn)的數(shù)據(jù)記錄集采用臨時表能提升系統(tǒng)性能。臨時表支持索引、 約束、排序等實體表具有的功能。 - 存儲特點:
? ? ? ?臨時表的數(shù)據(jù)存儲在 tempdb 數(shù)據(jù)庫中,因此過于頻繁的創(chuàng)建臨時表會增加 tempdb 庫的負(fù)荷,尤其是數(shù)據(jù)量超過 10W 條記錄的臨時表更是會影響 tempdb 庫的 性能,由此在某些情況下可用CTE 替代臨時表的使用。
注意事項:
? ? ? ?臨時表執(zhí)行完畢后,要及時的手工 Drop 掉,及時釋放資源,減輕系統(tǒng)的 Loading , 另外特別注意的是要盡量禁止使用全局臨時表,全局適合多個 session 間的數(shù)據(jù)交互, 但往往會引起數(shù)據(jù)的串值。 - 命名規(guī)范:
? ? ? ?盡量采用有意義的字段名,使描述盡可能清楚,如采用縮寫,盡量使用通用的縮 寫語言,如 addr 代表 address,避免出現(xiàn)只有自己理解的縮寫。 - 日期字段:
? ? ? ?時效性數(shù)據(jù)應(yīng)包括“創(chuàng)建時間/修改時間”字段,時間標(biāo)記對查找數(shù)據(jù)、清理數(shù)據(jù)、 排序合并特別有用,另外要根據(jù)具體業(yè)務(wù)考量時間字段的類型,如在 Smalldatetime和 Datetime 類型進(jìn)行選擇。 - 注意保留詞:
? ? ? ?對于字段的命名,要確保字段名沒有和保留詞、數(shù)據(jù)庫系統(tǒng)或者常用方法沖突, 比如 master 、CROSS 、address 、substring 、len 、sysobjects 等詞就不適合用來做字段 的獨立命名。 - 數(shù)值規(guī)范:
? ? ? ?數(shù)值型的主要有 INT 、BIGINT 、TINYINT 、SMALLINT 、FLOAT 、NUMERIC 、 MONEY 等類型,要根據(jù)實際應(yīng)用選擇合適的類型,如字段的數(shù)據(jù)為小于 255 的整形 數(shù)字,那么就要選擇 TINYINT;如字段數(shù)據(jù)小于 32767 的整形數(shù)字,那么就要選擇SMALLINT,以此類推。 - 文本規(guī)范:
? ? ? ?文本類型主要有 CHAR 、VARCHAR 、TEXT 等類型,要根據(jù)實際應(yīng)用選擇合適 的類型,如字段文本長度固定為 8 位,那么就要用CHAR(8);如文本長度最大為 100 , 并且大小是非定長的,那么就要設(shè)為 VARCHAR(100)。并且以上文本若為漢字,那 么就要設(shè)為 NVARCHAR 和 NCHAR 。 - 字段命名技巧:
? ? ? ?字段命名要統(tǒng)一規(guī)范,同一個字段在不同的表中命名要一致,另外字段名一般都 要帶上業(yè)務(wù)模塊的前綴,如訂單(Order)價格字段命名為 Or_Price,部門(Department)編 號為 Dep_No。命名規(guī)范沒有那個是最合理的,只有定義好最適合自己的統(tǒng)一規(guī)范即 可。
? ? ? ?外鍵建立索引:
外鍵不建立索引,將有可能導(dǎo)致兩個嚴(yán)重的問題。1.更新相關(guān)的表產(chǎn)生死鎖。2. 兩表關(guān)聯(lián)查詢時性能低下。因此通常情況下都必須要求外鍵建立索引。 - 聯(lián)合索引規(guī)范:
? ? ? ?當(dāng)數(shù)據(jù)對某表經(jīng)常要多條件查詢時,可能就需要建立聯(lián)合索引,聯(lián)合索引的第一 個引導(dǎo)列字段非常重要,引導(dǎo)列字段通常要能過濾掉大部分?jǐn)?shù)據(jù),這樣方能減少 IO 的讀寫,提高性能。非引導(dǎo)列字段在引導(dǎo)列的查詢數(shù)據(jù)基礎(chǔ)上繼續(xù)過濾數(shù)據(jù),以提高 查詢速度。聯(lián)合索引對更新會產(chǎn)生一定的性能影響。
禁用多余索引:
? ? ? ?數(shù)據(jù)庫索引能提高查詢速度,但會增加寫操作的開銷,因此對一些幾月或者從沒 有使用過的索引要刪除掉,以免增大數(shù)據(jù)庫的負(fù)荷。
重復(fù)索引問題:
? ? ? ?一般情況下,盡量避免重復(fù)索引的出現(xiàn),重復(fù)索引很容易引起死鎖,減低數(shù)據(jù)庫
的并發(fā)訪問。重復(fù)索引也會造成索引的維護困難。
索引數(shù)量限制:
? ? ? ?數(shù)據(jù)庫索引主要用來解決讀的性能瓶頸,但是會增加寫操作的負(fù)荷,因此過多的 索引會造成更新速度變慢,甚至?xí)鸩灰乃梨i。一般情況下表中的索引不要超過5 個。
注意事項:
? ? ? ?建立索引前,要充分了解表的使用及數(shù)據(jù)特性,要了解表的查詢條件和查詢頻率, 甚至隨著業(yè)務(wù)的變化而引起表數(shù)據(jù)使用狀況的變化,帶之而來的是索引也需要相應(yīng)調(diào)
整。 - 命名規(guī)范:
? ? ? ?存儲過程命名遵守統(tǒng)一的規(guī)范,對于業(yè)務(wù)存儲過程要以 p 或 proc開頭,接著加上” _ ”,然后再加上模塊名稱簡寫和具體的業(yè)務(wù)詞,最后加上執(zhí)行類型。
數(shù)據(jù)庫的存儲過程名嚴(yán)禁以 sp 開頭,sp 通常表示系統(tǒng)數(shù)據(jù)庫存儲過程名的前綴。觸 發(fā)器以 Tr 開頭,接著加上”_ ”,然后加上表名。 - 書寫規(guī)范:
? ? ? ?關(guān)鍵字建議用大寫,同樣的代碼書寫格式保持一致,SQL 腳本采用縮進(jìn)風(fēng)格,風(fēng) 格一致,縮進(jìn)格式一致,使用空格。
INSERT 規(guī)范:
? ? ? ?通常情況下,INSERT 語句要給出具體的字段列表,避免采用“INSERT INTO TB_1 VALUES( ‘值 1’, ’值 2’, ’值 3’)”用法,此種用法往往會由于表結(jié)構(gòu)變遷 而導(dǎo)致語句不可執(zhí)行
避免隱式轉(zhuǎn)換:
? ? ? ?書寫時,必須明確表結(jié)構(gòu)及表中各個字段的數(shù)據(jù)類型,特別是查詢條件中的字段,要避免由于類型的不同導(dǎo)致數(shù)據(jù)類型轉(zhuǎn)換的發(fā)生,從而減少因為
數(shù)據(jù)類型轉(zhuǎn)換產(chǎn)生的系統(tǒng)開銷。 - NULL 陷阱:
? ? ? ?NULL 不要直接用來進(jìn)行運算符的比較,也不要和其它值進(jìn)行連接操作,判斷一 個值是否為 NULL 值時,要采用IS NULL 來進(jìn)行比較。 - LIKE 規(guī)范:
? ? ? ?LIKE 子句應(yīng)盡量前段匹配,要避免通配符在前段,以免導(dǎo)致全索引掃描的發(fā)生。 - 參數(shù)化代碼:
? ? ? ?SQL 中常量的直接使用,會導(dǎo)致 SQL 語句頻繁的硬解析,進(jìn)而嚴(yán)重影響數(shù)據(jù)庫 的性能,基于這些原因,代碼中要盡量采用參數(shù)綁定,以減少語句硬解析的次數(shù),從 而提高語句執(zhí)行性能。 - 動態(tài) SQL:
? ? ? ?動態(tài) SQL 是在運行時才進(jìn)行解析的,相當(dāng)于是硬解析,因此會損失一些系統(tǒng)性 能,但是動態(tài) SQL 寫法靈活,因此在某些情況下需要以性能換靈活,但對于用靜態(tài) 語句就能簡單實現(xiàn)的 SQL,就不要用動態(tài)SQL 語句。 - 嵌套層級限制:
? ? ? ?嵌套查詢盡量少使用,尤其是對于超過 3 層的嵌套查詢更要慎用,對于復(fù)雜的嵌 套語句要根據(jù)業(yè)務(wù)進(jìn)行拆分為多條 SQL 來實現(xiàn),或者通過臨時表來取代一部分嵌套 層級。 - 排序規(guī)范:
? ? ? ?SQL 語句中要盡量減少排序,對查詢結(jié)果進(jìn)行的排序會大大降低系統(tǒng)的性能,并 且會增加 tempdb 數(shù)據(jù)庫的負(fù)荷,因此在開發(fā)時間寬松情況下,要盡量將排序動作放 到應(yīng)用程序?qū)尤ネ瓿伞?/li> - 代碼注釋要求:
? ? ? ?注釋是指程序中會被編譯器忽略掉的部分,目的是描述代碼的用途及更新時間, 合理的添加注釋可以使得程序結(jié)構(gòu)清晰,可以使代碼更好理解,便于系統(tǒng)后續(xù)的維護。 一般情況下,注釋要不少于代碼的十分之一。 - 靜態(tài) SQL:
? ? ? ?SQL 語句要盡可能采用靜態(tài) SQL,靜態(tài) SQL 第一次執(zhí)行時會將編譯器解析的結(jié) 果存儲在緩存中,下次執(zhí)行該靜態(tài) SQL 時會直接從緩存中獲取其執(zhí)行計劃,相當(dāng)于 是軟解析,因此采用靜態(tài) SQL 可以減少語句的解析時間,提升了數(shù)據(jù)庫的性能。 - 最小事務(wù)原則:
? ? ? ?數(shù)據(jù)庫事務(wù)用來保持?jǐn)?shù)據(jù)的一致性,但是對于一個執(zhí)行時間較長的大事務(wù),會造 成數(shù)據(jù)庫鎖的增加,當(dāng)鎖越積越多的時候就會從行鎖升級到頁鎖,從業(yè)鎖升級到表鎖, 從而嚴(yán)重影響數(shù)據(jù)庫的性能。因此,在能滿足數(shù)據(jù)一致性的前提下,要盡量將非一致
性要求的語句代碼從事務(wù)中移除,以便提升數(shù)據(jù)庫的并發(fā)訪問。 - 順序提交:
? ? ? ?順序提交是一個好的代碼編寫習(xí)慣,順序提交可以減少死鎖的發(fā)生,并且還能增 加代碼的可讀性及可維護性。
2、實訓(xùn)二:數(shù)據(jù)庫分析設(shè)計與建模
(1) 分析銀行 ATM 存取款系統(tǒng)實體
(2) 規(guī)范數(shù)據(jù)庫結(jié)構(gòu)設(shè)計
- 第一范式(1NF)是指數(shù)據(jù)庫表的每一列都是不可分割的基本數(shù)據(jù)項,同一列中 不能有多個值,即實體中的某個屬性不能有多個值或者不能有重復(fù)的屬性。
? ? ? ?如在銀行客戶表 BankCustomer 中,不能將客戶信息都放在一列中顯示,也不能 將其中的兩列或多列在一列中顯示;客戶信息表的每一行只表示一個員工的信息,一個客戶的信息在表中只出現(xiàn)一次。簡而言之,第一范式就是無重復(fù)的列。 - 第二范式(2NF)要求實體的屬性完全依賴于主關(guān)鍵字。
? ? ? ?如銀行交易信息表 BankDealInfo 中,不能把卡號設(shè)為主鍵因為一個卡號可以發(fā)生 多條交易記錄。要確定唯一的一條信息,必須重新定義一個和其它屬性無關(guān)的交易編 號。這樣要查詢一條交易信息。就可以用交易編號。簡而言之,第二范式就是屬性完全依賴于主鍵。 - 第三范式(3NF)要求一個數(shù)據(jù)庫表中不包含已在其它表中已包含的非主關(guān)鍵字 信息。
? ? ? ? 如銀行卡表 BankCard 中,有了用戶Id 后。不能還添加用戶姓名等相關(guān)的用戶信 息。否則就會有大量的數(shù)據(jù)冗余。簡而言之,第三范式就是屬性不依賴于其它非主屬性。
(3) 繪制 CDM 模型、生成 PDM 模型
3、實訓(xùn)三:創(chuàng)建數(shù)據(jù)庫
(1) 創(chuàng)建數(shù)據(jù)庫
? ? ? ?使用 Create DataBase 語句創(chuàng)建“ATM 存取款機系統(tǒng)”數(shù)據(jù)庫BankDB,數(shù)據(jù)文件和日志文件保存在指定目錄下文件增長率為 15% 。
--創(chuàng)建BankDB數(shù)據(jù)庫,數(shù)據(jù)庫文件和日志文件均保存在文件夾D:\data下 --文件增長率均為%,數(shù)據(jù)文件起始大小為MB,日志文件起始大小為MB create database BankDB on primary ( name=N'BankDB', filename=N'C:\data\BankDB.mdf', size=5mb, filegrowth=15% ) log on ( name=N'BankDB_log', filename=N'C:\data\BankDB_log.ldf', size=2mb, filegrowth=15% )(2) 創(chuàng)建各個數(shù)據(jù)表及相關(guān)的約束
? ? ? ?根據(jù)銀行業(yè)務(wù),分析表中每個列相應(yīng)的約束要求,為每個表添加各種約束。要求創(chuàng)建表時要求檢測是否存在表結(jié)構(gòu),如果存在,則先刪除再創(chuàng)建。
use BankDB go--判斷銀行客戶信息表是否存在,若存在則刪除 --sysobjects 系統(tǒng)對象表。保存當(dāng)前數(shù)據(jù)庫的對象。 --OBJECT_ID()根據(jù)對象名稱返回該對象的id IF EXISTS(SELECT * FROM sysobjects WHERE id=OBJECT_ID(N'BankCustomerInfo')) DROP TABLE BankCustomerInfo--創(chuàng)建BankCustomerInfo表 create table BankCustomerInfo( CustNum int identity(1,1) primary key not null, --客戶編號 CustName char(20) not null, --客戶姓名 CustID char(18) not null, --身份證號 CustTelephone char(20) not null, --客戶電話 CustAddress varchar(100) not null --客戶住址 )--判斷銀行卡表是否存在,若存在則刪除 IF EXISTS(SELECT * FROM sysobjects WHERE id=OBJECT_ID(N'BankCardInfo')) DROP TABLE BankCardInfo--創(chuàng)建BankCardInfo表 create table BankCardInfo( CardID char(19) primary key not null, --銀行卡號 Password char(6) not null, --密碼 MoneyType char(5) not null, --貨幣類型 DepositType int not null, --存款類型 OpenDate date not null, --開戶日期 OpenMoney money not null, --開戶金額 CardLoss char(10) not null, --是否掛失 CustNum int not null, --客戶編號 CardMoney numeric(8,2) not null --卡內(nèi)余額 )--判斷銀行交易信息表是否存在,若存在則刪除 IF EXISTS(SELECT * FROM sysobjects WHERE id=OBJECT_ID(N'BankDealInfo')) DROP TABLE BankDealInfo--創(chuàng)建BankDealInfo表 create table BankDealInfo( DealNum int identity(1,1) primary key not null, --交易編號 CardID char(19) not null, --銀行卡號 DealDate date not null, --交易日期 DealMoney decimal(8,2) not null, --交易金額 DealType char(256) not null, --交易類型 DealNote varchar(1024) null --交易備注 )--判斷業(yè)務(wù)類型表是否存在,若存在則刪除 IF EXISTS(SELECT * FROM sysobjects WHERE id=OBJECT_ID(N'BankBusinessType')) DROP TABLE BankBusinessType--創(chuàng)建BankBusinessType表 create table BankBusinessType( BusNum int identity(1,1) primary key not null, --業(yè)務(wù)編號 BusName char(20) not null, --業(yè)務(wù)名稱 BusDescribe varchar(100) null --業(yè)務(wù)描述 )--為BankCustomerInfo表添加約束 --添加check約束,身份證號前位必須是數(shù)字,后位可以是數(shù)字或者X alter table BankCustomerInfo add constraint ck_CustID check(left(CustID ,17) like '[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]' and (right(CustID ,1) like'[0-9]' or right(CustID,1) like 'X')) --客戶電話必須是固定電話號碼或者手機號 alter table BankCustomerInfo add constraint ck_CustTelephone check( CustTelephone like'[0-9][0-9][0-9][0-9]_[0-9][0-9][0-9][0-9][0-9][0-9][0-9]' or CustTelephone like '[0-9][0-9][0-9]_[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]' or CustTelephone like '1[358][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]') --銀行卡號前位必須為,后位為-9任意數(shù)字--為BankCardInfo表添加約束 alter table BankCardInfo add constraint ck_CardID check(CardID LIKE '1010 3576 [0-9][0-9][0-9][0-9] [0-9][0-9][0-9][0-9]') --密碼默認(rèn)為 alter table BankCardInfo add constraint df_Password default('888888') for Password --貨幣類型默認(rèn)為RMB alter table BankCardInfo add constraint df_MoneyType default('RMB') for MoneyType --開戶日期默認(rèn)為當(dāng)前時間 alter table BankCardInfo add constraint df_OpenDate default(getdate()) for OpenDate --開戶金額至少為元 alter table BankCardInfo add constraint ck_OpenMoney check(OpenMoney>=1) --是否掛失默認(rèn)為’否‘ alter table BankCardInfo add constraint df_CardLoss default('否') for CardLoss(3) 添加外鍵約束和生成數(shù)據(jù)庫關(guān)系圖
添加子表外鍵約束
--添加外鍵約束 alter table BankCardInfo add constraint fk_DepositType foreign key(DepositType) references BankBusinessType(BusNum) alter table BankCardInfo add constraint fk_CustNum foreign key(CustNum) references BankCustomerInfo(CustNum) alter table BankDealInfo add constraint fk_CardID foreign key(CardID) references BankCardInfo(CardID)在 SQL SERVER 里自動生成數(shù)據(jù)庫關(guān)系圖,如下圖所示:
4、實訓(xùn)四:創(chuàng)建觸發(fā)器和插入測試數(shù)據(jù)
(1) 創(chuàng)建級聯(lián)觸發(fā)器
創(chuàng)建 Insert 觸發(fā)器:
? ? ? ? 在交易信息表創(chuàng)建一個 insert 觸發(fā)器,當(dāng)增加一條交易信息時,修改相應(yīng)銀行卡
的存款余額。
創(chuàng)建Delete觸發(fā)器:
? ? ? ? 在交易信息表創(chuàng)建一個 Delete 觸發(fā)器,當(dāng)刪除一條交易信息時,修改相應(yīng)銀行卡
的存款余額。
創(chuàng)建 Update 觸發(fā)器
? ? ? ? 在交易信息表創(chuàng)建一個 Update 觸發(fā)器,當(dāng)更新一條交易信息時,修改相應(yīng)銀行 卡的存款余額。
(2) 插入數(shù)據(jù)表的測試數(shù)據(jù)
? ? ? ? 使用 T-SQL 語句向每個表插入如下所示測試數(shù)據(jù),要保證業(yè)務(wù)數(shù)據(jù)的一致性和 完整性。
BankBusinessType 表的測試數(shù)據(jù):
BankCustomerInfo 表的測試數(shù)據(jù):
BankCardInfo表的測試數(shù)據(jù):
insert into BankCardInfo (CardID,Password,MoneyType,DepositType,OpenDate,OpenMoney,CardLoss,CustNum,CardMoney) values ('1010 3576 1234 5678','197611','RMB',1,cast(dateadd(day,-(rand()*30),getdate()) as date),1000,'否',1,1000), ('1010 3576 1234 5688','197611','RMB',2,cast(dateadd(day,-(rand()*30),getdate()) as date),1000,'否',2,1500) go select * from BankCardInfo
BankDealInfo 表的測試數(shù)據(jù):
5、實訓(xùn)五:模擬常規(guī)業(yè)務(wù)
(1) 修改客戶密碼
? ? ? ?根據(jù)卡號修改指定 2 個客戶的銀行密碼,其中第一個客戶 1010 3576 1234 5678 密碼修改為 123456,第二個客戶 1010 3576 1234 5688 修改為 123123。
update BankCardInfo set Password='123465' where CardID='1010 3576 1234 5678' update BankCardInfo set Password='123123' where CardID='1010 3576 1234 5688' select CardID '銀行卡卡號',Password '密碼',MoneyType '貨幣類型',DepositType '儲蓄種類',OpenDate ' 開戶日期',OpenMoney '開戶金額', CardLoss '是否掛失',CustNum'客戶編號',CardMoney '存款金額' from BankCardInfo(2) 辦理銀行卡掛失
? ? ? ?卡號為 1010 3576 1234 5678 的銀行卡丟失,申請掛失。
update BankCardInfo set CardLoss='是' where CardID='1010 3576 1234 5678' select CardID '銀行卡卡號',Password'密碼',MoneyType '貨幣類型',BusName '儲蓄類型',OpenDate ' 開戶日期',OpenMoney '開戶金額', CardLoss '是否掛失',CustName'客戶姓名',CardMoney '存款 金額' from BankCardInfo inner join BankCustomerInfo on BankCardInfo.CustNum=BankCustomerInfo.CustNum inner join BankBusinessType on BankCardInfo.DepositType=BankBusinessType.BusNum(3) 統(tǒng)計銀行資金流通余額和盈利結(jié)算
存入代表資金流入,支取代表資金流出。
計算公式:資金流通余額=總存入金額-總支取金額
假定存款利率為千分之三,貸款利率為千分之八。
計算公式:盈利結(jié)算=總支取金額0.008-總存入金額0.003 。
要求創(chuàng)建一個存儲過程 proc_staticsBanlanceAndProfit 。
(4) 查詢本周開戶信息
查詢本周開戶的卡號,顯示該卡的相關(guān)信息。
--默認(rèn)星期日作為一周的第一天.修改星期一為第一天 set datefirst 1 select CardID '銀行卡卡號',CustName '姓名', MoneyType '貨幣類型',OpenDate '開戶時間 ',BusName '儲蓄類型',OpenMoney '開戶金額',CardMoney '存款金額', case CardLoss when '是' then '掛失賬戶' when '否' then '正常賬戶' end '是否掛失' from BankCardInfo inner join BankBusinessType on BankBusinessType.BusNum = BankCardInfo.DepositType inner join BankCustomerInfo on BankCustomerInfo.CustNum = BankCardInfo.CustNum where datediff(day,OpenDate,getdate())<datepart(weekday,getdate())(5) 查詢本月單次交易金額最高的卡號和總交易金額最高的卡號
查詢本月存、取款中單次交易金額最高的卡號信息。
select distinct BankDealInfo.CardID '銀行卡卡號',OpenDate '開戶日期',OpenMoney '開戶金額 ',DealMoney '單次最高金額' from BankCardInfo inner join BankDealInfo on BankDealInfo.CardID=BankCardInfo.CardID where DealMoney =(select max(DealMoney ) from BankDealInfo where datediff(month,DealDate,getdate())=0) select top 1 BankCardInfo.CardID '銀行卡卡號',OpenDate '開戶日期',OpenMoney '開戶金額 ',sum(DealMoney ) '總交易最高金額' from BankCardInfo inner join BankDealInfo on BankDealInfo.CardID=BankCardInfo.CardID where datediff(month,DealDate,getdate())=0 group by BankCardInfo.CardID,OpenDate,OpenMoney order by sum(DealMoney ) desc(6) 查詢掛失客戶
--子查詢 select CustName '客戶姓名',CustTelephone '聯(lián)系電話' from BankCustomerInfo where CustNum in (select CustNum from BankCardInfo where CardLoss='是') --內(nèi)連接 select CustName '客戶姓名',CustTelephone '聯(lián)系電話' from BankCustomerInfo inner join BankCardInfo on BankCardInfo.CustNum = BankCustomerInfo.CustNum where CardLoss='是'(7) 催款提醒業(yè)務(wù)
? ? ? ?根據(jù)某種業(yè)務(wù)(如代繳電話費、代繳手機費或房貸等)的需要,每個月末,查詢出客戶賬戶上余額少于 10000 元,由銀行統(tǒng)一致電催款。
select CustName '客戶姓名',CustTelephone '聯(lián)系電話',CardMoney '存款金額' from BankCardInfo inner join BankCustomerInfo on BankCustomerInfo.CustNum = BankCardInfo.CustNum where CardMoney<=100006、實訓(xùn)六:創(chuàng)建、使用視圖
(1) 輸出銀行客戶記錄視圖VW_userInfo
? ? ? ?顯示的列名全為中文,要求先判斷該視圖是否存在,若存在,則先刪除。
if object_id('vw_userinfo','v') is not null drop view vw_userinfo go create view vw_userinfo as select CustNum '客戶編號',CustName '開戶名',CustID '身份證號',CustTelephone '電話號碼',CustAddress '居住地址' from BankCustomerInfo go select * from vw_userinfo(2) 輸出銀行卡記錄視圖VW_CardInfo
if object_id('VW_CardInfo','v') is not null drop view VW_CardInfo go create view VW_CardInfo as select CardID '銀行卡卡號',CustName '姓名', MoneyType '貨幣類型',BusName '儲蓄類型 ',OpenDate '開戶日期',CardMoney '存款金額',Password'密碼', CardLoss '是否掛失' from BankCardInfo inner join BankCustomerInfo on BankCustomerInfo.CustNum = BankCardInfo.CustNum inner join BankBusinessType on BankBusinessType.BusNum = BankCardInfo.DepositType go select * from VW_CardInfo(3) 輸出銀行卡交易記錄視圖VW_TransInfo
if object_id('VW_TransInfo','v') is not null drop view VW_TransInfo go create view VW_TransInfo as select DealDate '交易日期',DealType '交易類型',CardID '銀行卡卡號',DealMoney'交易 金額',DealNote '備注' from BankDealInfo go select * from VW_TransInfo order by 交易日期(4) 根據(jù)客戶登錄名查詢該客戶賬戶信息VW_OneUserInfo
? ? ? ?根據(jù)客戶登錄名(采用實名制訪問銀行系統(tǒng))查詢該客戶賬戶信息的視圖,利用SQL SERVER 系統(tǒng)函數(shù) system_user 獲得數(shù)據(jù)庫用戶名。
if object_id('VW_OneUserInfo','v') is not null drop view VW_OneUserInfo go create view VW_OneUserInfo as select CustNum '客戶編號',CustName '開戶名',CustID '身份證號',CustTelephone '電話號碼',CustAddress '居住地址' from BankCustomerInfo where CustName=system_user go select * from VW_OneUserInfo7、實訓(xùn)七:存儲過程實現(xiàn)業(yè)務(wù)處理
(1) 完成存款或取款業(yè)務(wù)
描述:
? ? ? ? 根據(jù)銀行卡號和交易金額實現(xiàn)銀行卡的存款和取款業(yè)務(wù)。
? ? ? ? 每一筆存款,取款業(yè)務(wù)都要計入銀行交易賬,并同時更新客戶的存款余額。
? ? ? ? 如果是取款業(yè)務(wù),在記賬之前,要完成下面兩項數(shù)據(jù)的檢查驗證工作,如果檢查 不合格,那么中斷取款業(yè)務(wù),給出提示信息后退出。
? ? ? ? 檢查客戶輸入的密碼是否正確。
? ? ? ? 賬戶取款金額是否大于當(dāng)前存款額加 1 。
(2) 產(chǎn)生隨機卡號
? ? ? ? 創(chuàng)建存儲過程產(chǎn)生 8 位隨機數(shù)字,與前 8 位固定數(shù)字“1010 3576”連接,生成一個由 16 位數(shù)字組成的銀行卡號,并輸出。
if object_id('proc_RandCardID','p') is not null drop procedure proc_RandCardID go --創(chuàng)建隨機卡號的存儲過程 create procedure proc_RandCardID @randcardid char(19) output as declare @r numeric(8,8),@tmpstr char(10) --產(chǎn)生隨機種子=當(dāng)前的月份數(shù)*100000+當(dāng)前的秒數(shù)*1000+當(dāng)前的毫秒數(shù) set @r=rand(datepart(month,getdate())*100000+datepart(second,getdate())*1000+datepart(millisecond,getdate())) set @tmpstr=convert(char(10),@r) set @randcardid='1010 3576 '+substring(@tmpstr,3,4)+' '+substring(@tmpstr,7,4) go declare @mycardid1 char(19) exec proc_RandCardID @mycardid1 output print '產(chǎn)生隨機卡號為'+@mycardid1(3) 完成開戶業(yè)務(wù)
描述:
? ? ? ? 利用存儲過程為客戶開設(shè) 2 個銀行卡賬戶,開戶時需要提供客戶的信息有:開戶 名、身份證號、電話號碼、開戶金額、存款類型和地址。客戶的信息見表所示:
? ? ? ? 為成功開戶的客戶提供銀行卡,且銀行卡號唯一。
(4) 分頁顯示查詢交易數(shù)據(jù)
? ? ? ? 根據(jù)指定的頁數(shù)和每頁的記錄數(shù)分頁顯示交易數(shù)據(jù)。
if object_id('proc_PagingDisplay','p') is not null drop procedure proc_PagingDisplay go create procedure proc_PagingDisplay @page int,@count int as select rownumber '交易編號',DealDate '交易日期',DealType '交易類型',CardID '銀行卡卡號 ',DealMoney'交易金額' from (select row_number() over(order by DealNum) rownumber,DealDate,DealType,CardID,DealMoney from BankDealInfo) c where c.rownumber between (@page-1)*@count+1 and @page*@count go exec proc_PagingDisplay @page = 2,@count = 5(5) 統(tǒng)計未發(fā)生交易的賬戶
? ? ? ? 查詢統(tǒng)計指定時間段內(nèi)沒有發(fā)生交易的賬戶信息
if object_id('proc_getwithouttrade','p') is not null drop procedure proc_getwithouttrade go create procedure proc_getwithouttrade @startdate datetime=null,@enddate datetime=null as declare @name char(16),@icno char(18),@tel char(15),@addr char(50),@moneysum money=0,@customersum int=0,@money int if (@startdate is null) set @startdate=convert(datetime,convert(char(8),getdate(),120)+'1') if (@enddate is null) set @enddate=getdate() --有的客戶未交易.所以用右連接或者全連接 declare cur_outtrade cursor for select distinct CustName,CustID,CustTelephone,CustAddress,CardMoney from BankDealInfo right join BankCardInfo on BankCardInfo.CardID=BankDealInfo.CardID right join BankCustomerInfo on BankCustomerInfo.CustNum = BankCardInfo.CustNum where BankDealInfo.CardID not in(select BankDealInfo.CardID from BankDealInfo where DealDate>=@startdate and DealDate<=@enddate) print convert(char(16),'客戶姓名')+convert(char(20),'身份證號')+convert(char(16),'電 話')+convert(char(20),'地址') open cur_outtrade fetch next from cur_outtrade into @name,@icno,@tel,@addr,@money while @@fetch_status=0 begin print convert(char(16),@name)+convert(char(20),@icno)+convert(char(16),@tel)+convert(char(20),@addr) set @moneysum=@moneysum+@money set @customersum=@customersum+1 fetch next from cur_outtrade into @name,@icno,@tel,@addr,@money end print '統(tǒng)計未發(fā)生交易的客戶' print '客戶人數(shù):'+ltrim(str(@customersum))+',客戶總余額:'+ltrim(str(@moneysum)) close cur_outtrade deallocate cur_outtrade go exec proc_getwithouttrade @startdate='2015-8-19',@enddate='2015-9-19' exec proc_getwithouttrade8、實訓(xùn)八:利用事務(wù)實現(xiàn)轉(zhuǎn)賬
? ? ? ? 使用存儲過程和事務(wù)實現(xiàn)轉(zhuǎn)賬業(yè)務(wù),操作步驟如下所示:
? ? ? ? (1)從某一個賬戶支取一定金額的存款。
? ? ? ? (2)將支取金額存入到另一個指定的賬戶中。
? ? ? ? (3)分別打印此筆業(yè)務(wù)的轉(zhuǎn)出賬單和轉(zhuǎn)入賬單
總結(jié)
以上是生活随笔為你收集整理的课程设计:基于SQL Server的银行ATM 存取款机系统设计与实现的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 什么是大数据,大数据到底应该如何学?
- 下一篇: 【OpenCV 例程200篇】33. 图