事情開始得很簡單。MegaWare公司市場部門想要一個新的網站來發布文檔,開發團隊覺得使用SQL Server 2000數據庫作為文檔存儲倉庫會使事情變得簡單。Steve是MegaWare的數據庫管理員,沒有看出這有什麼大問題;在數據庫中存儲文檔,而不是使用文件系統,意味著服務器需要多做一些工作,但是它也會使得備份和管理容易得多。數據庫與文件系統變得不同步也應該是不可能的。
市場部門想要存儲的許多文檔都超過了8000個字節,那麼很明顯VARCHAR不是適合這項工作的數據類型。作為替代,TEXT數據類型被用來定義存放數據的字段。因為每個TEXT都能容納2GB的內容,TEXT要存放市場部門的同事們扔進數據庫的最大的文件也是沒有問題的。
數月過去了,市場用大量的無聊拷貝填滿了整個數據庫。但是這還不是Steve真正關心的問題。數據庫愉快地嗡嗡作響地運轉著,每個人對項目的結果都很滿意。
直到公司的標語改變的那個重大的日子。市場部的團隊認為“MegaWare: It's really cool!”要比原來的“It's MegaWare's Way or the Highway!” 聽起來更好。因為市場部團隊已經將原來的標語嵌入了倉庫中每個文檔的頁腳上,現在Steve的工作就是更改所有這些文檔的頁腳。
“沒有問題,” Steve想,打開SQL Server 查詢分析器工具,執行了如下的T-SQL批處理:
UPDATE MarketingDocuments
SET Document =
REPLACE(Document,
'It''s MegaWare''s Way or the Highway!',
'MegaWare: It''s really cool!)
當他看到出現的錯誤消息的時候,Steve的輕松的微笑很快消失了,“替換函數的參數1,text數據類型無效。”
替換函數在編寫出來的時候,就對TEXT數據類型不起作用。同樣也對CHARINDEX或者SUBSTRING不起作用――或者至少是他們在超過8千個字符的情況下不起作用。更進一步地講,開發人員忘了處理TEXT或者IMAGE類型的本地變量;實際上不支持任何操作。即使是簡單地更新一個文檔中的一個子字符串都需要用到晦澀的東西,以及難以使用的類似READTEXT和WRITETEXT的函數。而不是開發人員或者忙碌的數據庫管理員因為想要弄清如何正確使用而采用了不同類型的函數消耗了時間。
SQL Server的開發人員很幸運,他們將會撥開烏雲見藍天。SQL Server 2005引入了一系列新的被稱為MAX的數據類型。這是VARCHAR,NVARCHAR和VARBINARY類型的擴展,這幾種類型以前被限制在8000字節以下。MAX可以容納高達2GB的數據,與TEXT和IMAGE一樣――並且完全兼容所有的SQL Server內置的字符串函數。
用MAX關鍵字定義一個某種MAX類型的變量與替代字符串的尺寸(為VARCHAR/NVARCHAR的時候)或者字節(為VARBINARY的時候)一樣簡單。
DECLARE @BigString VARCHAR(MAX)
SET @BigString = 'abc'
雖然這個變量可以自由地操縱,並且可以傳遞給任何的內置的字符串函數,兼容性仍然不是沒有問題。首先,開發人員不能期望指定了尺寸的VARCHAR和VARBINARY變量在達到8000個字節的極限的時候可以自動“升級”到MAX版本。例如,如下的批處理:
DECLARE @String1 VARCHAR(4001)
DECLARE @String2 VARCHAR(4001)
SET @String1 = REPLICATE('1', 4001)
SET @String2 = REPLICATE('2', 4001)
SELECT LEN(@String1 + @String2)
4001+4001=8002,但是指定了尺寸的VARCHAR的極限是8000。因為這兩個變量中沒有一個是MAX類型,LEN函數的結果就是8000,不是8002。在將兩個變量連接的時候,一種簡單的修正方法就是聲明這兩個變量中的一個為VARCHAR(MAX)或者將其中的一個變量進行轉換。與一個規定了尺寸的類型進行連接的時候,優先考慮MAX類型,最終結果是MAX類型。所以,以下批處理的結果是8002,正如我們期望的一樣:
DECLARE @String1 VARCHAR(4001)
DECLARE @String2 VARCHA