對於設計和建立數據庫徹底是個新手?不要緊,Joe Celko, 世界上讀者數量最多的SQL做者之一,會告訴你這些基礎。和往常同樣,即便是最專業的數據庫老手,也會給他們帶來驚喜。Joe是DMBS雜誌是多年來最受 讀者喜好的做者。他在美國、英國,北歐,南美及非洲傳授SQL知識。他在ANSI / ISO SQL標準委員會工做了10年,爲SQL-89和SQL-92標準作出了傑出貢獻。程序員
Joe Celko會談下數據庫設計裏存儲過程和它的位置。他所寫的是使人深思的東西,即便是有經驗的數據庫開發人員。sql
在第一篇,咱們因它們是什麼並區分它們命名數據元。在第二篇,咱們用SQL裏給咱們的數據類型和簡單的行或列約束來模型化數據元。在第三篇,咱們把這些行放入表成爲實體,關係和輔助數據。在第四篇,咱們有了基礎表,把它們鏈接在一塊兒,增長從索引,並建立了視圖。數據庫
這應該會給你萬事俱備,倒是錯誤的感受。在一個很是簡單的數據庫裏,這是對的。但在一個真正的數據庫有更多的架構來考慮。在這些架構外的其餘東西事:遊標(cursors)、觸發器(triggers)和存儲過程(stored procedures)。有更多像整理、翻譯,特權和諸如此類的東西。我將只處理這3個東西——遊標(cursors)、觸發器(triggers)和存儲過程(stored procedures)——我只用一般的方式命名。儘管ANS/ISO標準裏,T-SQL和其餘產品能夠得到更高的佔有慾。理由很簡單:這些東西創建在早期SQL產品使用的現有文件系統上。這些程序結構是用來彌補在早期產品裏缺乏申明式代碼。這些供應商有鎖在今天「代碼博物館」不能地址他們客戶羣的用戶。編程
SQL容許存儲過程代碼模塊在架構裏保存。同時在標準SQL裏有SQL/PSM語言,你會使用像T-SQL的專門語言。這些語言一般是Algol家族的成員;那就是說他它們有IF-THEN-ELSE,WHILE循環和有BEGIN-END做用域的代碼塊。數據結構
這些專用語言的大多數從未想用作程序開發。對於T-SQL的首要規則(The rules of thumb)是不寫超過50行的的過程,且不使用PRINT。但事實上,你能夠避免全部的面向過程,每一個表像文件和代碼同樣對待,好像數據庫是個過程化的文件系統。若是你喜歡疼痛,大可敲個釘子到你身體,因此不用糾結。架構
存儲過程的目的更像個視圖。它們授予全部用戶在全部時間會用一樣的方式作一樣的工做。視圖封裝了一個查詢並給它一個名稱,所以建立了一個虛擬表。存儲過程用一樣的方式封裝了UPDATE,INSERT,DELETE和SELECT,但增長了參數。數據庫設計
在存儲過程名稱裏一個參數(parameter )就是個「持有人(place holder)」,參數值(argument )是傳給存儲過程的實際值。T-SQL參數過去只限制於簡單的標量值。如今,它們能夠是表值和XML字符。讓咱們從簡單的標量參數開始。編程語言
編譯器讀取參數值,並檢查數據類型,範圍和確保它是有效的其餘事項。編譯器會作比你想象還多的事。看下這個T-SQL:ide
1 SELECT ISDATE ('2010-01-01'); -- TRUE 2 SELECT CAST ('2010-01-01' AS DATE); -- no problem 3 SELECT ISDATE ('010-01-01'; --TRUE 4 SELECT CAST ('010-01-01' AS DATE); -- error
同事,浮點表示法有點意思。若是你以DECIMAL或FLOAT轉化指數計數法,確定沒問題:函數
1 SELECT CAST (62.3E8 AS DECIMAL(18,5)); -- returns 6230000000.00000 2 SELECT CAST (62.3E8 AS FLOAT); -- returns 6230000000
但如今把字符串的指數計數法,嘗試轉化它爲DECIMAL或FLOAT,你確定會出現問題:
1 SELECT CAST ('62.3E8' AS DECIMAL(18,5)); -- error 2 SELECT CAST ('62.3E8' AS FLOAT); -- returns 6230000000
若是轉化字符,你要用這樣的指數代碼:
1 SELECT CAST(CAST ('62.3E8' AS FLOAT) AS DECIMAL(18,5)); -- 6230000000.00000
如今嘗試傳這些測試值做爲參數,看看它們的結果:
1 CREATE PROCEDURE Test 2 (@in_test_date DATE, 3 @in_test_decimal DECIMAL(18,5)) 4 AS 5 BEGIN 6 SELECT @in_test_date, @in_test_decimal; 7 END;
EXEC Test '2010-01-01', 62.3E8;
返回值(2010-01-01, 6230000000.00000)和預期的同樣。
你不能傳表達式做爲參數值,但你能夠傳本地變量,它是表達式值預先設置的。這就是說這個會報錯:
EXEC Test '2010-01-01', 62.3 * POWER(10, 8) ;
但這個會成功執行:
1 BEGIN 2 DECLARE @local_decimal DECIMAL (18,5); 3 SET @local_decimal = 62.3 * POWER(10, 8); 4 EXEC Test '2010-01-01', @local_decimal ; 5 END;
你會看到新的SQL編程會嘗試傳遞XML或CSV(逗號分割值(Comma Separated Values))列表字符做爲參數值。它們增長了解析器的負擔(XML解析器或任何寫出來用來分割CSV字符的任何代碼)並讓它們的數據完整性受到危險。SQL Server能夠處理超過2000的參數值,對於現實中的狀況已經足夠能應付。
在參數列表裏另外一個未使用的功能是默認值。這個語法很是簡單。參數聲明後一個「=」和一個合適的定值。
若是參數值沒有提供,就會使用默認值。
CREATE PROCEDURE Test (@in_test_date DATE = '2010-01-01', @in_test_decimal DECIMAL(18,5) = 0.00000 ) AS BEGIN SELECT @in_test_date, @in_test_decimal; END;
除非你特別分配參數值到參數,它們是從左到右的順序分配。
EXEC Test; -- returns (2010-01-01, 0.00000) EXEC Test '2010-12-25' -- returns (2010-12-25, 0.00000) EXEC Test @in_test_date = 789; -- returns (2010-01-01, 789.00000)
最後,參數能夠用做輸出。這就是說它須要在調用的模塊裏有個本地變量,這樣的話,返回值纔有地方可去。這是展現這個語法的例子:
1 CREATE PROCEDURE Test 2 (@in_test_date DATE OUTPUT, 3 @in_test_decimal DECIMAL(18,5) OUTPUT) 4 AS 5 BEGIN 6 SET @in_test_date = '2010-12-25'; 7 SET @in_test_decimal = 789; 8 END; 9 10 BEGIN 11 DECLARE @local_date DATE; 12 DECLARE @local_decimal DECIMAL(18,5); 13 SELECT @local_date, @local_decimal; --returns (NULL, NULL) 14 EXEC Test @local_date OUTPUT, @local_decimal OUTPUT 15 SELECT @local_date, @local_decimal; -- returns (2010-12-25, 789.00000) 16 END;
關於存儲過程標題就講這些;那存儲過程的具體內容呢?嗯,咱們如今暫時不講。咱們先講下原則讓,而後再看看特定的工具。咱們須要一個高度來看如何編寫代碼——軟件工程(Software Engineering)。
軟件工程的基礎不在SQL裏修改。但現實徹底不同。咱們大多數(從學LISP,APL,FP,Haskell或其它外來語言學起,對這些程序員例外)學過從Algol-60進化而來的結構化編程語言。適用於過程化語言的原則一樣適用於SQL存儲過程。
在近1970年,咱們發現咱們能夠在程序裏寫出更好(更快,正確,更易維護的)的代碼,在代碼裏有本地代碼塊規則和代碼模塊,都是一個入口一個出口。咱們避免GO TO語句,並使用簡單的一系列控制結構。這是結構化編程的進步。
內聚度是一個模塊作且只作一件事會很好:那是邏輯上的內聚性。模塊應該高內聚。模塊的命名格式應該是「<動做><對象>」,這裏「<對象>」是數據模型裏特定的邏輯單元,「<動做>」是單一明確的行動。有不少內聚類型。咱們從最差到最好對它們排名。
若是在你的軟件工程課程裏錯過這些,你能夠網上找下它們的具體定義。
耦合度是模塊之間的相互獨立性。若是你的模塊須要特定的順序執行,它們是強耦合度。若是它們之間能夠獨立運行,能夠像樂高同樣堆積,它們是鬆散或弱耦合的。耦合有好幾類,從低到高排序是:
這個在個人《SQL 編程風格》書裏關於存儲過程編寫的章節裏會有簡單的介紹。同時,你也能夠閱讀下DeMarco, Yourdon, Constantine, Myers或其它軟件工程先驅。這已經不是簡單的SQL編程了。在你寫任何語言的代碼前,這些都是你應該知道的。
通常而言,好的存儲過程是高內聚,低耦合,它不使用控制結構的缺陷,除非是必須的。對於過程化開發人員,這個是意外。理由是儘量多的把「編程的元素」放入單純的SQL,這樣優化器能夠更好的處理代碼。
如何實現?下篇會告訴你。
http://www.sqlservercentral.com/articles/Stairway+Series/Procedures+in+Database+design/70891/