博客

  • SQL語法大全

    本部分內容
                SQL基礎
               中級SQL
               高級SQL
    第10章SQL基礎

                     本章內容
               
                      SQL介紹
                     使用SELECT語句從表中取數據
                     創建新表
                     字段屬性
                     向表中添加數據
                     刪除和修改表
             

        為了建立交互站點,你需要使用數據庫來存儲來自訪問者的信息。例如,你要建立一個職業介紹服務的站點,你就需要存儲諸如個人簡歷,所感興趣的工作等等這樣的信息。創建動態網葉也需要使用數據庫,如果你想顯示符合來訪者要求的最好的工作,你就需要從數據庫中取出這份工作的信息。你將會發現,在許多情況下需要使用數據庫。
        在這一章裡,你將學會怎樣使用“結構化查詢語言”(SQL〕來操作數據庫。SQL語言是數據庫的標準語言。在Active Sever Pages中,無論何時你要訪問一個數據庫,你就要使用SQL語言。因此,掌握好SQL對ASP編程是非常重要的。
         
        注意:
        你可以把“SQL”讀作“sequel”,也可以按單個字母的讀音讀作S-Q-L。兩種發音都是正確的,每種發音各有大量的支持者。在本書裡,認為“SQL”讀作“sequel”。

        通過這一章的學習,你將理解怎樣用SQL實現數據庫查詢,你將學會怎樣使用這種查詢從數據表中取出信息,最後,你將學會怎樣設計和建立自己的數據庫。
                
        注意:
        通過下面幾章對SQL的介紹,你將對SQL有足夠的了解,從而可以有效地使用Active Sever Pages。但是,SQL是一種複雜的語言,本書不可能包括它的全部細節。要全面掌握SQL語言,你需要學習在Microsoft SQL Sever中使用SQL。你可以到附近的書店去買一本Microsoft SQL Sever 6.5。

    SQL介紹:
        本書假設你是在SQL操作Microsoft SQL Sever的數據庫。你也可以用SQL操作許多其它類型的數據庫。 SQL是操作數據庫的標準語言。 (事實上,關於SQL語言有一個專門的ANSI標準〕

        注意:
        不要在你的站點上試圖用Microsoft Access代替Microsoft SQL Sever。 SQL Sever可以同時服務於許多用戶,如果你希望你的站點有較高的訪問率,MS Access是不能勝任的。

        在學習SQL的細節之前,你需要理解它的兩大特點。一個特點容易掌握,另一個掌握起來有點困難。
        第一個特點是所有SQL數據庫中的數據都存儲在表中。一個表由行和列組成。例如,下面這個簡單的表包括name和e-mail address:
         Name Email Address
         ………………………………………….. …………..
         Bill Gates billg@microsoft.com
         president Clinton president@whitehouse.com
         Stephen Walther swalther@somewhere.com
        這個表有兩列(列也稱為字段,域〕:Name和Email Address。有三行,每一行包含一組數據。一行中的數據組合在一起稱為一條記錄。
        無論何時你向表中添加新數據,你就添加了一條新記錄。一個數據表可以有幾十個記錄,也可以有幾千甚至幾十億個記錄。雖然你也許永遠不需要存儲十億個Email地址,但知道你能這樣做總是好的,也許有一天你會有這樣的需要。
        你的數據庫很有可能包含幾十個表,所有存儲在你數據庫中的信息都被存儲在這些表中。當你考慮怎樣把信息存儲在數據庫中時,你應該考慮怎樣把它們存儲在表中。
         SQL的第二個特點有些難於掌握。這種語言被設計為不允許你按照某種特定的順序來取出記錄,因為這樣做會降低SQL Sever取記錄的效率。使用SQL,你只能按查詢條件來讀取記錄。
        當考慮如何從表中取出記錄時,自然會想到按記錄的位置讀取它們。例如,也許你會嘗試通過一個循環,逐個記錄地掃描,來選出特定的記錄。在使用SQL時,你必須訓練自己,不要有這種思路。
        假如你想選出所有的名字是“Bill Gates”的記錄,如果使用傳統的編程語言,你也許會構造一個循環,逐個查看表中的記錄,看名字域是否是“Bill Gates”。
        這種選擇記錄的方法是可行的,但是效率不高。使用SQL,你只要說,“選擇所有名字域等於Bill Gates的記錄”,SQL就會為你選出所有符合條件的記錄。 SQL會確定實現查詢的最佳方法。
        建設你想取出表中的前十個記錄。使用傳統的編程語言,你可以做一個循環,取出前十個記錄後結束循環。但使用標準的SQL查詢,這是不可能實現的。從SQL的角度來說,在一個表中不存在前十個記錄這種概念。
        開始時,當你知道你不能用SQL實現某些你感覺應該能實現的功能,你會受到挫折。你也許會以頭撞牆甚至想寫惡毒的信件給SQL的設計者們。但後來你會認識到,SQL的這個特點不僅不是個限制,反而是其長處。因為SQL不根據位置來讀取記錄,它讀取記錄可以很快。
        綜上所述,SQL有兩個特點:所有數據存儲在表中,從SQL的角度來說,表中的記錄沒有順序。在下一節,你將學會怎樣用SQL從表中選擇特殊的記錄。

    使用SQL從表中取記錄。
         SQL的主要功能之一是實現數據庫查詢。如果你熟悉Internet引擎,那麼你已經熟悉查詢了。你使用查詢來取得滿足特定條件的信息。例如,如果你想找到有ASP信息的全部站點,你可以連接到Yahoo!並執行一個對Active Sever Pages的搜索。在你輸入這個查詢後,你會收到一個列表,表中包括所有其描述中包含搜索表達式的站點。
        多數Internet引擎允許邏輯查詢。在邏輯查詢中,你可以包括特殊的運算符如AND、OR和NOT,你使用這些運算符來選擇特定的記錄。例如,你可以用AND來限制查詢結果。如果你執行一個對Active Sever Pages AND SQL的搜索。你將得到其描述中同時包含Active Sever Pages和SQL的記錄。當你需要限制查詢結果時,你可以使用AND。
        如果你需要擴展查詢的結果,你可以使用邏輯操作符OR。例如,如果你執行一個搜索,搜索所有的其描述中包含Active Sever Pages OR SQL的站點,你收到的列表中將包括所有其描述中同時包含兩個表達式或其中任何一個表達式的站點。
        如果你想從搜索結果中排除特定的站點,你可以使用NOT。例如,查詢“Active Sever Pages ”AND NOT “SQL”將返回一個列表,列表中的站點包含Active Sever Pages,但不包含SQL。當必須排除特定的記錄時,你可以使用NOT。
        用SQL執行的查詢與用Internet搜索引擎執行的搜索非常相似。當你執行一個SQL查詢時,通過使用包括邏輯運算符的查詢條件,你可以得到一個記錄列表。此時查詢結果是來自一個或多個表。
         SQL查詢的句法非常簡單。假設有一個名為email_table的表,包含名字和地址兩個字段,要得到Bill Gates的e_mail地址,你可以使用下面的查詢:

         SELECT email from email_table WHERE name=”Bill Gates”

        當這個查詢執行時,就從名為email_table的表中讀取Bill Gates的e_mail地址。這個簡單的語句包括三部分:
         ■ SELECT語句的第一部分指名要選取的列。在此例中,只有email列被選取。當執行時,只顯示email列的值billg@microsoft.com。
         ■ SELECTT語句的第二部份指明要從哪個(些)表中查詢數據。在此例中,要查詢的表名為email_table 。
         ■最後,SELECT語句的WHERE子句指明要選擇滿足什麼條件的記錄。在此例中,查詢條件為只有name列的值為Bill Gates的記錄才被選取。
         Bill Gates很有可能擁有不止一個email地址。如果表中包含Bill Gates的多個email地址。用上述的SELECT語句可以讀取他所有的email地址。 SELECT語句從表中取出所有name字段值為Bill Gates的記錄的email字段的值。
        前面說過,查詢可以在查詢條件中包含邏輯運算符。假如你想讀取Bill Gates或Clinton總統的所有email地址,你可以使用下面的查詢語句:

         SELECT email FROM email_table WHERE name=”Bill Gates” OR
                                                        name=”president Clinton”

        此例中的查詢條件比前一個複雜了一點。這個語句從表email_table中選出所有name列為Bill Gates或president Clinton的記錄。如果表中含有Bill Gates或president Clinton的多個地址,所有的地址都被讀取。
         SELECT語句的結構看起來很直觀。如果你請一個朋友從一個表中為你選擇一組記錄,你也許以非常相似的方式提出你的要求。在SQL SELECT語句中,你“SELECT特定的列FROM一個表WHERE某些列滿足一個特定的條件”。
        下一節將介紹怎樣執行SQL查詢來選取記錄。這將幫助你熟悉用SELECT語句從表中取數據的各種不同方法。

    使用ISQL執行SELECT查詢
        當你安裝SQL Sever時,你同時安裝了一個叫作ISQL/w的應用程序。 ISQL/w允許你執行交互的SQL查詢。在把查詢包括到你的ASP網頁中之前,用ISQL/w對其進行測試是非常有用的。

        注意:
        在這本書的第一部份,你學習了怎樣安裝和配置Microsoft SQL Sever 。如果沒有安裝SQL Sever或者SQL Sever不能運行,請參閱第三章“安裝和使用SQL Sever”。

        選擇任務上SQL Sever程序組中的ISQL_w以啟動該程序。程序啟動時,首先會出現一個對話框,要求輸入服務器信息和登錄信息(見圖10.1)。在Sever框中,輸入你的SQL服務器的名字。如果服務器正運行在本地計算機上,服務器名字就是你計算機的名字。在登錄信息框中,輸入一個登錄帳號和密碼或選擇使用“可信連接”,然後單擊Connect按鈕。

        圖10。1

        注意:
        如果你將SQL Sever配置為使用完整安全或混合安全,那麼你可以使用可信連接。如果你使用標準安全,你則需要提供用戶帳號和密碼。要了解更多信息,參見第三章。

        如果一切正常,在你單擊連接按鈕後會出現一個查詢窗口,如圖10.2所示。 (如果有異常,請參考第三章)

            圖10.2

        在執行查詢之前,你需要選擇數據庫。安裝SQL Sever時你已為自己創建了一個數據庫,SQL Sever還有許多系統數據庫,如master,model,msdb,和tempdb。
        方便的是,SQL Sever帶有一個特殊的名為pubs的例子數據庫。庫pubs中包含供一個虛擬的出版商使用的各個表。文檔中所有的例子程序都是針對這個庫來設計的。本書中的許多例子也使用這個數據庫。
        在查詢窗口頂部的DB下拉框中選擇數據庫pubs,這樣你就選擇了數據庫。你所有的查詢都將針對這個庫中的各個表來執行。現在你可以執行你的第一個查詢了。這真讓人興奮!
        你的第一個查詢將針對一個名為autrors的表,表中包含所有為某個虛擬出版商工作的作者的相關數據。單擊查詢窗口並輸入以下的語句:

         SELECT phone FROM authors WHERE au_name=”Ringer”

        輸入完成後,單擊執行查詢按鈕(一個綠色三角形,看起來像VCR播放鍵)。單擊此按鈕後,任何出現在查詢窗口中的語句均會被執行。查詢窗口會自動變成結果顯示窗口,你可以看到查詢的結果(見圖10.3)。
        你看到的查詢結果也許與圖10.3所示的不同。在SQL Sever的不同版本中,庫pubs中的數據會有所不同。對SQL Sever 6.5來說,將會找到兩條記錄。結果顯示窗口中應顯示如下內容:
        
         phone
    ……………….
    801 826_0752
    801 826_0752
         (2 row(s) affected)

      
     
      圖10.3

        你所執行的SELECT語句從表authors中取出所有名字為Ringer的作者的電話號碼。你通過在WHERE子句中使用特殊的選擇條件來限制查詢的結果。你也可以忽略選擇條件,從表中取出所有作者的電話號碼。要做到這一點,單擊Query標籤,返回到查詢窗口,輸入以下的SELECT語句:

    SELECT Phone FROM authors
        這個查詢執行後,會取出表authors中的所有電話號碼(沒有特定的順序)。如果表authors中包含一百個電話號碼,會有一百個記錄被取出,如果表中有十億個電話號碼,這十億條記錄都會被取出(這也許需要一些時間)。
        表authrs的字段包括姓,名字,電話號碼,地址,城市,州和郵政編碼。通過在SELECT語句的第一部份指定它們,你可以從表中取出任何一個字段。你可以在一個SELECT語句中一次取出多個字段,比如:

         SELECT au_fname ,au_lname, phone FROM authors

        這個SELECT語句執行後,將取出這三個列的所有值。下面是這個查詢的結果的一個示例(為了節省紙張,只顯示查詢結果的一部分,其餘記錄用省略號代替):

         au_fname au_lname phone
         ………………………………………………………………………….
         Johnson White 408 496_7223
         Marjorie Green 415 986_7020
         Cheryl Carson 415 548_7723
         Michael O’Leary 408 286_2428
         …
         (23 row(s) affected)

        在SELECT語句中,你需要列出多少個字段,你就可以列出多少。不要忘了把字段名用逗號隔開。你也可以用星號(*)從一個表中取出所有的字段。這裡有一個使用星號的例子:

         SELECT * FROM authors

        這個SELECT語句執行後,表中的所有字段的值都被取出。你會發現你將在SQL查詢中頻繁使用星號。

        技巧:
        你可以使用星號來查看一個表的所有列的名字。要做到這一點,只需要在執行完SELECT語句後看一下查詢結果的列標題。

    操作多個表
        到現在為止,你只嘗試了用一句SQL查詢從一個表中取出數據。你也可以用一個SELECT語句同時從多個表中取出數據,只需在SELECT語句的FROM從句中列出要從中取出數據的表名稱即可:
            
         SELECT au_lname ,title FROM authors, titles

        這個SELECT語句執行時,同時從表authors和表titles中取出數據。從表authors中取出所有的作者名字,從表titles中取出所有的書名。在ISQL/w程序中執行這個查詢,看一下查詢結果。你會發現一些奇怪的出乎意料的情況:作者的名字並沒有和它們所著的書相匹配,而是出現了作者名字和書名的所有可能的組合,這也許不是你所希望見到的。
        出了什麼差錯?問題在於你沒有指明這兩個表之間的關係。你沒有通過任何方式告訴SQL如何把表和表關聯在一起。由於不知道如何關聯兩個表,服務器只能簡單地返回取自兩個表中的記錄的所有可能組合。
        要從兩個表中選出有意義的記錄組合,你需要通過建立兩表中字段的關係來關聯兩個表。要做到這一點的途徑之一是創建第三個表,專門用來描述另外兩個表的字段之間的關係。
        表authors有一個名為au_id的字段,包含有每個作者的唯一標識。表titles有一個名為title_id的字段,包含每個書名的唯一標識。如果你能在字段au_id和字段title_id之間建立一個關係,你就可以關聯這兩個表。數據庫pubs中有一個名為titleauthor的表,正是用來完成這個工作。表中的每個記錄包括兩個字段,用來把表titles和表authors關聯在一起。下面的SELECT語句使用了這三個表以得到正確的結果:

         SELECT au_name,title FROM authors,titles,titleauthor
                                 WHERE authors.au_id=titleauthor.au_id
                                  AND titles.title_id=titleauthor.title_id

        當這個SELECT語句執行時,每個作者都將與正確的書名相匹配。表titleauthor指明了表authors和表titles的關係,它通過包含分別來自兩個表的各一個字段實現這一點。第三個表的唯一目的是在另外兩個表的字段之間建立關係。它本身不包含任何附加數據。
        注意在這個例子中字段名是如何書寫的。為了區別表authors和表titles中相同的字段名au_id,每個字段名前面都加上了表名前綴和一個句號。名為author.au_id的字段屬於表authors,名為titleauthor.au_id的字段屬於表titleauthor,兩者不會混淆。
        通過使用第三個表,你可以在兩個表的字段之間建立各種類型的關係。例如,一個作者也許寫了許多不同的書,或者一本書也許由許多不同的作者共同完成。當兩個表的字段之間有這種“多對多”的關係時,你需要使用第三個表來指明這種關係。
        但是,在許多情況下,兩個表之間的關係並不復雜。比如你需要指明表titles和表publishers之間的關係。因為一個書名不可能與多個出版商相匹配,你不需要通過第三個表來指明這兩個表之間的關係。要指明表titles和表publishers之間的關係,你只要讓這兩個表有一個公共的字段就可以了。在數據庫pubs中,表titles和表publishers都有一個名為pub_id的字段。如果你想得到書名及其出版商的一個列表,你可以使用如下的語句:
         SELECT title,pub_name FROM titles,publishers
                                 WHERE titles.pub_id=publishers.pub_id

        當然,如果一本書是由兩個出版商聯合出版的,那麼你需要第三個表來代表這種關係。
        通常,當你予先知道兩個表的字段間存在“多對多”關係時,就使用第三個表來關聯這兩個表。反之,如果兩個表的字段間只有“一對一”或“一對多”關係,你可以使用公共字段來關聯它門。

    操作字段
        通常,當你從一個表中取出字段值時,該值與創建該表時所定義的字段名聯繫在一起。如果你從表authors中選擇所有的作者名字,所有的值將會與字段名au_lname相聯繫。但是在某些情況下,你需要對字段名進行操作。在SELECT語句中,你可以在缺省字段名後面僅跟一個新名字來取代它。例如,可以用一個更直觀易讀的名字Author Last Name來代替字段名au_lname:

         SELECT au_lname “Author Last Name” FROM authors

        當這個SELECT語句執行時,來自字段au_lname的值會與“Author Last Name”相聯繫。查詢結果可能是這樣:
             
           Author Last Name
           ……………………………………………………………………..
           White
           Green
           Carson
           O’Leary
           Straight
           …
           (23 row(s) affected)
     
    注意字段標題不再是au_lname,而是被Author Last Name所取代。
        你也可以通過執行運算,來操作從一個表返回的字段值。例如,如果你想把表titles中的所有書的價格加倍,你可以使用下面的SELECT語句:
        
         SELECT price*2 FROM titles

        當這個查詢執行時,每本書的價格從表中取出時都會加倍。但是,通過這種途徑操作字段不會改變存儲在表中的書價。對字段的運算只會影響SELECT語句的輸出,而不會影響表中的數據。為了同時顯示書的原始價格和漲價後的新價格,你可以使用下面的查詢:

    SELECT price “Original price”, price*2 “New price” FROM titles

        當數據從表titles中取出時,原始價格顯示在標題Original price下面,加倍後的價格顯示在標題New price下面。結果可能是這樣:
              
           original price new price
           ……………………………………………………………….
    19.99 39.98
    11.95 23.90
    2.99 5.98
    19.99 39.98

    (18 row(s) affected)
            
        你可以使用大多數標準的數學運算符來操作字段值,如加(+),減(-),乘(*)和除(/)。你也可以一次對多個字段進行運算,例如:

          SELECT price*ytd_sales “total revenue” FROM titles

        在這個例子中,通過把價格與銷售量相乘,計算出了每種書的總銷售額。這個SELECT語句的結果將是這樣的:
           
           total revenue
           ……………………………………………..
           81,859,05
           46,318,20
           55,978,78
           81,859,05
           40,619,68
           …
           (18 row(s) affected)
      
        最後,你還可以使用連接運算符(它看起來像個加號)來連接兩個字符型字段:

           SELECT au_fname+” “+au_lname “author name” FROM authors

        在這個例子中,你把字段au_fname和字段au_lname粘貼在一起,中間用一個逗號隔開,並把查詢結果的標題指定為author name。這個語句的執行結果將是這樣的:

            author names
            …………………………………………………………
            Johnson White
            Marjorie Green
            Cheryl Carson
           Michael O’Leary
           Dean Straight
           …
           (23 row(s) affected)
     
        可以看到,SQL為你提供了對查詢結果的許多控制。你應該在ASP編程過程中充分利用這些優點。使用SQL來操作查詢結果幾乎總是比使用有同樣作用的腳本效率更高。

    排序查詢結果
        本章的介紹中曾強調過,SQL表沒有內在的順序。例如,從一個表中取第二個記錄是沒有意義的。從SQL的角度看來,沒有一個記錄在任何其他記錄之前。
    然而,你可以操縱一個SQL查詢結果的順序。在缺省情況下,當記錄從表中取出時,記錄不以特定的順序出現。例如,當從表authors中取出字段au_lname時,查詢結果顯示成這樣:

            au_lname
            …………………………………….
            White
            Green
            Carson
            O’Leary
            Straight
            …
            (23 row(s) affected)
       
        看一列沒有特定順序的名字是很不方便的。如果把這些名字按字母順序排列,讀起來就會容易得多。通過使用ORDER BY子句,你可以強制一個查詢結果按升序排列,就像這樣:

         SELECT au_lname FROM authors ORDER BY au_lname

        當這個SELECT語句執行時,作者名字的顯示將按字母順序排列。 ORDER BY子句將作者名字按升序排列。
        你也可以同時對多個列使用ORDER BY子句。例如,如果你想同時按升序顯示字段au_lname和字段au_fname,你需要對兩個字段都進行排序:

         SELECT au_lname,au_fname FROM authors ORDER BY au_lname ,au_fname

        這個查詢首先把結果按au_lname字段進行排序,然後按字段au_fname排序。記錄將按如下的順序取出:

           au_lname au_fname
           …………………………………………………………………….
           Bennet Abraham
           Ringer Albert
           Ringer Anne
           Smith Meander
           …
           (23 row(s) affected)

        注意有兩個作者有相同的名字Ringer。名為Albert Ringer的作者出現名為Anne Ringer的作者之前,這是因為姓Albert按字母順序應排在姓Anne之前。
    如果你想把查詢結果按相反的順序排列,你可以使用關鍵字DESC。關鍵字DESC把查詢結果按降序排列,如下例所示:
         
            SELECT au_lname,au_fname FROM authors
                   WHERE au_lname=”Ringer” ORDER BY au_lname ,au_fname DESC

        這個查詢從表authors中取出所有名字為Ringer的作者記錄。 ORDER BY子句根據作者的名字和姓,將查詢結果按降序排列。結果是這樣的:

           au_lname au_fname
           ……………………………………………………………………………………….
           Ringer Anne
           Ringer Albert
           (2 row(s) affectec)

        注意在這個表中,姓Anne出現在姓Albert之前。作者名字按降序顯示。
    你也可以按數值型字段對一個查詢結果進行排序。例如,如果你想按降序取出所有書的價格,你可以使用如下的SQL查詢:

            SELECT price FROM titles ORDER BY price DESC

        這個SELECT語句從表中取出所有書的價格,顯示結果時,價格低的書先顯示,價格高的書後顯示。

        警告:
        不是特別需要時,不要對查詢結果進行排序,因為服務器完成這項工作要費些力氣。這意味著帶有ORDER BY子句的SELECT語句執行起來比一般的SELECT語句花的時間長。

    取出互不相同的記錄
        一個表有可能在同一列中有重複的值。例如,數據庫pubs的表authors中有兩個作者的名字是Ringer。如果你從這個表中取出所有的名字,名字Ringer將會顯示兩次。
        在特定情況下,你可能只有興趣從一個表中取出互不相同的值。如果一個字段有重複的值,你也許希望每個值只被選取一次,你可以使用關鍵字DISTINCT來做到這一點:

          SELCET DISTINCT au_lname FROM authors WHERE au_lname=”Ringer”

        當這個SELECT語句執行時,只返回一個記錄。通過在SELECT語句中包含關鍵字DISTINCT,你可以刪除所有重複的值。例如,假設有一個關於新聞組信息發布的表,你想取出所有曾在這個新聞組中發布信息的人的名字,那麼你可以使用關鍵字DISTINCT。每個用戶的名字只取一次——儘管有的用戶發布了不止一篇信息。
        警告:
        如同ORDER BY子句一樣,強制服務器返回互不相同的值也會增加運行開銷。福氣不得不花費一些時間來完成這項工作。因此,不是必須的時候不要使用關鍵字DISTINCT。

    創建新表
        前面說過,數據庫中的所有數據存儲在表中。數據表包括行和列。列決定了表中數據的類型。行包含了實際的數據。
        例如,數據庫pubs中的表authors有九個字段。其中的一個字段名為為au_lname,這個字段被用來存儲作者的名字信息。每次向這個表中添加新作者時,作者名字就被添加到這個字段,產生一條新記錄。
        通過定義字段,你可以創建一個新表。每個字段有一個名字和一個特定的數據類型(數據類型在後面的“字段類型”一節中講述),例如字段au_lname存儲的是字符型數據。一個字段也可以存儲其它類型的數據。
        使用SQL Sever,創建一個新表的方法是很多的。你可以可執行一個SQL語句或使用SQL事務管理器(SQL Enterprise Manager)來創建一個新表。在下一節裡,你將學會如何用SQL語句來創建一個新表。

    用SQL創建新表
        注意:
        如果你還沒有建立自己的數據庫,現在就跳回到第三章創建這個庫。你絕不能向master,tempdb或任何其他任何系統數據庫中添加數據。

        從SQL Sever程序組(在任務欄中)中啟動ISQL/w程序。出現查詢窗口後,從窗口頂部的下拉列表中選擇你在第三章所創建的數據庫。下一步,在查詢窗口中鍵入下面的SQL語句,單擊執行查詢按鈕,執行這個語句:

           CREATE TABLE guestbook (visitor VARCHAR(40),comments TEXT,entrydate
                                              DATETIME)

    如果一切正常,你會在結果窗口中看到如下的文字(如果出現異常,請參閱第三章):

           This command dit not return data ,and it did not return any rows

    祝賀你,你已經建立了你的第一個表!
        你所創建的表名為guestbook,你可以使用這個表來存儲來字你站點訪問者的信息。你是用REEATE TABLE語句創建的這個表,這個語句有兩部分:第一部份指定表的名子;第二部份是括在括號中的各字段的名稱和屬性,相互之間用逗號隔開。
        表guestbook有三個字段:visitor,comments和entrydate。 visitor字段存儲訪問者的名字,comments字段存儲訪問者對你站點的意見,entrydate字段存儲訪問者訪問你站點的日期和時間。
        注意每個字段名後面都跟有一個專門的表達式。例如,字段名comments後面跟有表達式TEXT。這個表達式指定了字段的數據類型。數據類型決定了一個字段可以存儲什麼樣的數據。因為字段comments包含文本信息,其數據類型定義為文本型。
        字段有許多不同的數據類型。下一小節講述SQL所支持的一些重要的數據類型。

    字段類型
        不同的字段類型用來存放不同類型的數據。創建和使用表時,更你應該理解五種常用的字段類型:字符型,文本型,數值型,邏輯性和日期型。

    字符型數據
        字符型數據非常有用。當你需要存儲短的字符串信息時,你總是要用到字符型數據。例如,你可以把從HTML form的文本框中蒐集到的信息放在字符型字段中。
        要建立一個字段用來存放可變長度的字符串信息,你可以使用表達式VARCHAR。考慮你前面創建的表guestbook:

          CREATE TABLE guestbook (visitor VARCHAR(40),comments TEXT,entrydate
                                              DATETIME)

        在這個例子中,字段visitor的數據類型為VARCHAR。注意跟在數據類型後面的括號中的數字。這個數字指定了這個字段所允許存放的字符串的最大長度。在這個例子中,字段visitor能存放的字符串最長為四十個字符。如果名字太長,字符串會被截斷,只保留四十個字符。
         VARCHAR類型可以存儲的字符串最長為255個字符。要存儲更長的字符串數據,可以使用文本型數據(下一節中講述)。
        另一種字符型數據用來存儲固定長度的字符數據。下面是一個使用這種數據類型的例子:

          CREATE TABLE guestbook (visitor CHAR(40),comments TEXT,entrydate
                                              DATETIME)

        在這個例子中,字段visitor被用來存儲四十個字符的固定長度字符串。表達式CHAR指定了這個字段應該是固定長度的字符串。
         VARCHAR型和CHAR型數據的這個差別是細微的,但是非常重要。假如你向一個長度為四十個字符的VARCHAR型字段中輸入數據Bill Gates。當你以後從這個字段中取出此數據時,你取出的數據其長度為十個字符——字符串Bill Gates的長度。
        現在假如你把字符串輸入一個長度為四十個字符的CHAR型字段中,那麼當你取出數據時,所取出的數據長度將是四十個字符。字符串的後面會被附加多餘的空格。
        當你建立自己的站點時,你會發現使用VARCHAR型字段要比CHAR型字段方便的多。使用VARCHAR型字段時,你不需要為剪掉你數據中多餘的空格而操心。
         VARCHAR型字段的另一個突出的好處是它可以比CHAR型字段佔用更少的內存和硬盤空間。當你的數據庫很大時,這種內存和磁盤空間的節省會變得非常重要。

    文本型數據
        字符型數據限制了字符串的長度不能超過255個字符。而使用文本型數據,你可以存放超過二十億個字符的字符串。當你需要存儲大串的字符時,應該使用文本型數據。
        這裡有一個使用文本型數據的例子:

         CREATE TABLE guestbook (visitor VARCHAR(40),comments TEXT,entrydate
                                              DATETIME)

        在這個例子中,字段comments被用來存放訪問者對你站點的意見。注意文本型數據沒有長度,而上一節中所講的字符型數據是有長度的。一個文本型字段中的數據通常要么為空,要么很大。
        當你從HTML form的多行文本編輯框(TEXTAREA)中收集數據時,你應該把收集的信息存儲於文本型字段中。但是,無論何時,只要你能避免使用文本型字段,你就應該不適用它。文本型字段既大且慢,濫用文本型字段會使服務器速度變慢。文本型字段還會吃掉大量的磁盤空間。
        警告:
        一旦你向文本型字段中輸入了任何數據(甚至是空值),就會有2K的空間被自動分配給該數據。除非刪除該記錄,否則你無法收回這部分存儲空間。

    數值型數據
         SQL Sever支持許多種不同的數值型數據。你可以存儲整數、小數、和錢數。
        通常,當你需要在表中的存放數字時,你要使用整型(INT)數據。 INT型數據的表數範圍是從-2,147,483,647到2,147,483,647的整數。下面是一個如何使用INT型數據的例子:

            CREATE TABLE visitlog (visitor VARCHAR(40),numvisits INT)

        這個表可以用來記錄你站點被訪問的次數。只要沒有人訪問你的站點超過2,147,483,647次,nubvisits字段就可以存儲訪問次數。
        為了節省內存空間,你可以使用SMALLINT型數據。 SMALLINT型數據可以存儲從-32768到32768的整數。這種數據類型的使用方法與INT型完全相同。
        最後,如果你實在需要節省空間,你可以使用TINYINT型數據。同樣,這種類型的使用方法也與INT型相同,不同的是這種類型的字段只能存儲從0到255的整數。 TINYINT型字段不能用來存儲負數。
        通常,為了節省空間,應該盡可能的使用最小的整型數據。一個TINYINT型數據只佔用一個字節;一個INT型數據佔用四個字節。這看起來似乎差別不大,但是在比較大的表中,字節數的增長是很快的。另一方面,一旦你已經創建了一個字段,要修改它是很困難的。因此,為安全起見,你應該預測以下,一個字段所需要存儲的數值最大有可能是多大,然後選擇適當的數據類型。
        為了能對字段所存放的數據有更多的控制,你可以使用NUMERIC型數據來同時表示一個數的整數部分和小數部分。 NUMERIC型數據使你能表示非常大的數——比INT型數據要大得多。一個NUMERIC型字段可以存儲從-1038到1038範圍內的數。 NUMERIC型數據還使你能表示有小數部分的數。例如,你可以在NUMERIC型字段中存儲小數3.14。
        當定義一個NUMERIC型字段時,你需要同時指定整數部分的大小和小數部分的大小。這裡有一個使用這種數據類型的例子:
         
            CREATE TABLE numeric_data (bignumber NUMERIC(28,0),
                                        fraction NUMERIC (5,4) )

        當這個語句執行時,將創建一個名為numeric_data的包含兩個字段的表。字段bignumber可以存儲直到28位的整數。字段fraction可以存儲有五位整數部分和四位小數部分的小數。
        一個NUMERIC型數據的整數部分最大隻能有28位,小數部分的位數必須小於或等於整數部分的位數,小數部分可以是零。
        你可以使用INT型或NUMERIC型數據來存儲錢數。但是,專門有另外兩種數據類型用於此目的。如果你希望你的網點能掙很多錢,你可以使用MONEY型數據。如果你的野心不大,你可以使用SMALLMONEY型數據。 MONEY型數據可以存儲從-922,337,203,685,477.5808到922,337,203,685,477.5807的錢數。如果你需要存儲比這還大的金額,你可以使用NUMERIC型數據。
         SMALLMONEY型數據只能存儲從-214,748.3648到214,748.3647的錢數。同樣,如果可以的話,你應該用SMALLMONEY型來代替MONEY型數據,以節省空間。下面的例子顯示瞭如何使用這兩種表示錢的數據類型:

           CREATE TABLE products (product VARCHAR(40),price MONEY,
                                    Discount_price SMALLMONEY)

        這個表可以用來存儲商品的折扣和普通售價。字段price的數據類型是MONEY,字段discount_price的數據類型是SMALLMONEY。

    存儲邏輯值
        如果你使用複選框(CHECKBOX)從網頁中蒐集信息,你可以把此信息存儲在BIT型字段中。 BIT型字段只能取兩個值:0或1。這裡有一個如何使用這種字段的例子:

         CREATE TABLE opinion (visitor VARCHAR(40),good BIT)

        這個表可以用來存放對你的網點進行民意調查所得的信息。訪問者可以投票表示他們是否喜歡你的網點。如果他們投YES,就在BIT型字段中存入1。反之,如果他們投NO,就在字段中存入0(在下一章裡,你將學會如何計算投票)。
        當心,在你創建好一個表之後,你不能向表中添加BIT型字段。如果你打算在一個表中包含BIT型字段,你必須在創建表時完成。

    存儲日期和時間
        當你建立一個網點時,你也許需要記錄在一段時間內的訪問者數量。為了能夠存儲日期和時間,你需要使用DATETIME型數據,如下例所示:

         CREATE TABL visitorlog( visitor VARCHAR (40), arrivaltime DATETIME ,
                                    departuretime DATETIME)

        這個表可以用來記錄訪問者進入和離開你網點的時間和日期。一個DATETIME型的字段可以存儲的日期範圍是從1753年1月1日第一毫秒到9999年12月31日最後一毫秒。
        如果你不需要覆蓋這麼大範圍的日期和時間,你可以使用SMALLDATETIME型數據。它與DATETIME型數據同樣使用,只不過它能表示的日期和時間範圍比DATETIME型數據小,而且不如DATETIME型數據精確。一個SMALLDATETIME型的字段能夠存儲從1900年1月1日到2079年6月6日的日期,它只能精確到秒。
         DATETIME型字段在你輸入日期和時間之前並不包含實際的數據,認識這一點是重要的。在下一章,你將學習怎樣使用大量的SQL函數來讀取和操作日期和時間(參見下面的“缺省值”一節)。你也可以在VBScript和JScript中使用日期和時間函數來向一個DATETIME型字段中輸入日期和時間。

    字段屬性
        上一節介紹瞭如何建立包含不同類型字段的表。在這一節中,你將學會如何使用字段的三個屬性。這些屬性允許你控制空值,缺省值和標識值。

    允許和禁止空值
        大多數字段可以接受空值(NULL)。當一個字段接受了空值後,如果你不改變它,它將一直保持空值。空值(NULL)和零是不同的,嚴格的說,空值表示沒有任何值。
    為了允許一個字段接受空值,你要在字段定義的後面使用表達式NULL。例如,下面的表中兩個字段都允許接受空值:
          
           CREATE TABLE empty (empty1 CHAR (40) NULL,empty2 INT NULL(
       
        注意:
         BIT型數據不能是空值。一個這種類型的字段必須取0或者1。

        有時你需要禁止一個字段使用空值。例如,假設有一個表存儲著信用卡號碼和信用卡有效日期,你不會希望有人輸入一個信用卡號碼但不輸入有效日期。為了強制兩個字段都輸入數據,你可以用下面的方法建立這個表:
          
           CREATE TABLE creditcards (creditcard_number CHAR(20) NOT NULL,
                                      Creditcard_expire DATETIME NOT NULL)
        注意字段定義的後面跟有表達式NOT NULL。通過包含表達式NOT NULL,你可以禁止任何人只在一個字段中插入數據,而不輸入另一個字段的數據。
        你將會發現,在你建設自己的網點過程中,這種禁止空值的能力是非常有用的。如果你指定一個字段不能接受空值,那麼當你試圖輸入一個空值時,會有錯誤警告。這些錯誤警告可以為程序調試提供有價值的線索。

    缺省值
        假設有一個存儲地址信息的表,這個表的字段包括街道、城市、州、郵政編碼和國家。如果你預計地址的大部分是在美國,你可以把這個值作為country字段的缺省值。
        為了在創建一個表時指定缺省值,你可以使用表達式DEFAULT。請看下面這個在創建表時使用缺省值的例子:
           
           CREATE TABLE addresses (street VARCHAR(60) NULL,
                                    city VARCHAR(40) NULL,
                                    state VARCHAR(20) NULL
                                    zip VARCHAR(20) NULL,
                                    country VARCHAR(30) DEFAULT ‘USA’)

        在這個例子中,字段country的缺省值被指定為美國。注意單引號的使用,引號指明這是字符型數據。為了給非字符型的字段指定缺省值,不要把該值擴在引號中:
        
           CREATE TABLE orders(price MONEY DEFAULT $38.00,
                                quantity INT DEFAULT 50,
                                 entrydate DATETIME DEFAULT GETDATE())

        在這個CREATE TABLE語句中,每個字段都指定了一個缺省值。注意DATETIME型字段entrydate所指定的缺省值,該缺省值是函數Getdate()的返回值,該函數返回當前的日期和時間。

    標識字段
        每個表可以有一個也只能有一個標識字段。一個標識字段是唯一標識表中每條記錄的特殊字段。例如,數據庫pubs中的表jobs包含了一個唯一標識每個工作標識字段:
        
           job_id job_desc
           …………………………………………………………….
    1 New Hire Job not specified
    2 Chief Executive officer
    3 Bushness Operations Manager
    4 Chief Financial Officier
    5 Publisher
     
        字段job_id為每個工作提供了唯一的一個數字。如果你決定增加一個新工作,新增記錄的job_id字段會被自動賦給一個新的唯一值。
        為了建立一個標識字段,你只需在字段定義後面加上表達式IDENTITY即可。你只能把NUMERIC型或INT型字段設為標識字段,這裡有一個例子:
      
            CREATE TABLE visitorID (theID NUBERIC(18) IDENTITY,name VARCHAR(40))
       
        這個語句所創建的表包含一個名為theid的標識字段。每當一個新的訪問者名字添加到這個表中時,這個字段就被自動賦給一個新值。你可以用這個表為你的站點的每一個用戶提供唯一標識。
        技巧:
        建立一個標示字段時,注意使用足夠大的數據類型。例如你使用TINYINT型數據,那麼你只能向表中添加255個記錄。如果你預計一個表可能會變得很大,你應該使用NUMERIC型數據。

        標識字段的存在會使你想嘗試許多不可能的事情。例如,你也許想利用標識字段來對記錄進行基於它們在表中位置的運算。你應該拋棄這種意圖。每個記錄的標識字段的值是互不相同的,但是,這並不禁止一個標識字段的標識數字之間存在間隔。例如,你永遠不要試圖利用一個表的標識字段來取出表中的前十個記錄。這種操作會導致失敗,比如說6號記錄和7號記錄根本不存在。

    使用SQL事務管理器創建新表
        你可以使用前面幾節所講的方法創建新表。但是,使用事務管理器創建新表會更容易。這一節介紹如何使用這個程序創建新表。
        從任務欄的SQL Sever程序組中選擇SQL Enterprise Manager,啟動該程序,你會看到如圖10.4所示的窗口。瀏覽服務管理器窗口中的樹形結構,選擇名為Database的文件夾。打開文件夾Database後,選擇你在第三章中所建立的數據庫。
        
    注意:
        如果你還沒有創建自己的數據庫,回到第三章創建它。你決不要向master,tempdb或任何其它系統數據庫中添加數據。
      
        在選擇了數據庫之後,你會看到一個名為Group/users的文件夾和一個名為objects的文件夾。打開文件夾objects,你會看到許多文件夾,其中一個名為Tables。用右鍵單擊文件夾Tables並選擇New table,就會出現如圖10.5所示的窗口。
        你可以使用Manager Tables窗口來創建一個新表。 Manager Tables窗口有7個列:Key,Column,Name,Datatype,Size,Nulls和Default。 Manager Tables窗口中的每一行標明表中一個字段的信息。

            圖10.4
                10.5

        要建立一個新表,你至少要輸入一行信息。在名為Column Name的列下面鍵入mycolumn。下一步,選擇Datatype列,並從下拉列表中選擇CHAR。當你在這兩個列中輸入信息後,窗口將是如圖10.6所示的樣子。

     圖10.6

        你已經建立了一個只有一個字段的簡單的表。單擊保存按扭保存這個新表。當要求你輸入新表的名字時,輸入mytable並單擊OK。現在這個表已經保存到了你的數據庫中。
    如果你打開服務管理器窗口中的文件夾Tables,你會看到你所建立的新表被列出。你可以雙擊該表的圖表來編輯它,這時Manager Tables窗口會重新出現,你可以增加新的字段並重新保存。
        用SQL事務管理器可以做的工作,你都可以用SQL語句來實現。但是,事務管理器使得建表過程變得更加簡單。

    向表中添加數據
        下一章將討論如何使用SQL向一個表中插入數據。但是,如果你需要向一個表中添加許多條記錄,使用SQL語句輸入數據是很不方便的。幸運的是,Microsoft SQL Sever帶有一個稱為Microsoft Query的客戶端應用程序,這個程序使得向表中添加數據變得容易了。
        啟動位於任務欄SQL Sever程序組中的Microsoft Query程序。從窗口頂部的菜單中選擇File|New Query。這時會顯示一個Select Data Source對話框(見圖10.7)。選擇你的數據源名字並單擊Use。
        
    圖10。7

        輸入你的登錄帳號和密碼後,程序要求你選擇一個表和一個數據庫。選擇你在上一節中所建立的表(mytable ),單擊按鈕Add,然後單擊按鈕Close關閉該對話框。
        在窗口的左上角會出現一個對話框,框中是取自表mytable的一列字段名。你可以雙擊任何一個字段,把它添加到主窗口中。如果你雙擊星號(*)字符,所有的字段都會被添加到主窗口中。
        如果你的表中有記錄,它們現在已經出現在主窗口的字段標題下面了。但是,因為你剛剛建立了這個表,表還是空的。要添加新記錄,選擇Records|Allow Editing,主窗口中就會出現一條新記錄。輸入一行數據完成這個記錄,就向表中添加了一條新記錄。
           
                    圖10。8

        當你轉到下一條新記錄時,你向上一條記錄中輸入的值會自動被保存。如果你需要,你可以用Microsoft Query向表中輸入幾百條記錄。

    刪除和修改表
        你應該在建立表之前仔細設計它們,因為你在改變一個已經存在的表時會受到很大的限制。例如,一旦已經建立了一個表,你就不能刪除表中的字段或者改變字段的數據類型。在這種情況你所能做的是刪除這個表,然後重頭開始(參見第十一章“中級SQL”中的“使用SQL創建記錄和表”一節)。
        要刪除一個表,你可以使用SQL語句DROP TABLE。例如,又從數據庫中徹底刪除表mytable,你要使用如下的語句:
        
            DROP TABLE mytable

        警告:
        使用DROP TABLE命令時一定要小心。一旦一個表被刪除之後,你將無法恢復它。

        當你建設一個站點時,你很可能需要向數據庫中輸入測試數據。而當你準備向世界提供你的網點時,你會想清空表中的這些測試信息。如果你想清除表中的所有數據但不刪除這個表,你可以使用TRUNCATE TABLE語句。例如,下面的這個SQL語句從表mytable中刪除所有數據:

             TRUNCATE TABLE mytable

        雖然你不能刪除和修改已經存在的字段,但你可以增加新字段。最容易的實現方法是使用SQL事務管理器中的Manager Tables窗口。你也可以使用SQL語句ALTER TABLE。下面是一個如何使用這種語句的例子:

          ALTER TABLE mytable ADD mynewcolumn INT NULL

        這個語句向表mytable中增加了一個新字段mynewcolumn。當你增加新字段時,你必須允許它接受空值,因為表中原來可能已經有了許多記錄。

    總結
        這一章向你介紹了SQL。使用SQL,你可以操作Microsoft SQL Sever數據庫。你已經學會了使用SELECT語句從數據庫中取出數據,你還學會了怎樣使用CREATE TABLE語句和SQL事務管理器來創建新表。最後,你學會瞭如何指明一系列重要的字段屬性。
    下一章將介紹如何使用索引來增強SQL查詢的操作。還將通過許多其它的SQL語句和函數,使你的SQL知識得到進一步擴充。

     

    第十一章中級SQL

                   本章內容
                    ■創建索引
                    ■SQL核心語句
                    ■集合函數
    ■其它常用的SQL表達式,
      函數,和過程

     

        第十章“SQL基礎”向你初步介紹了SQL。你學會瞭如何用SELECT語句進行查詢,你還學會瞭如何建立自己的表。在這一章裡,你將加深你的SQL知識。你將學習如何建立索引來加快查詢速度。你還將學會如果用更多的SQL語句和函數來操作表中的數據。

    建立索引
        假設你想找到本書中的某一個句子。你可以一頁一頁地逐頁搜索,但這會花很多時間。而通過使用本書的索引,你可以很快地找到你要搜索的主題。
        表的索引與附在一本書後面的索引非常相似。它可以極大地提高查詢的速度。對一個較大的表來說,通過加索引,一個通常要花費幾個小時來完成的查詢只要幾分鐘就可以完成。因此沒有理由對需要頻繁查詢的表增加索引。
        注意:
        當你的內存容量或硬盤空間不足時,也許你不想給一個表增加索引。對於包含索引的數據庫,SQL Sever需要一個可觀的額外空間。例如,要建立一個聚簇索引,需要大約1.2倍於數據大小的空間。要看一看一個表的索引在數據庫中所佔的空間大小,你可以使用系統存儲過程sp_spaceused,對象名指定為被索引的表名。

    聚簇索引和非聚簇索引
        假設你已經通過本書的索引找到了一個句子所在的頁碼。一旦已經知道了頁碼後,你很可能漫無目的翻尋這本書,直至找到正確的頁碼。通過隨機的翻尋,你最終可以到達正確的頁碼。但是,有一種找到頁碼的更有效的方法。
        首先,把書翻到大概一半的地方,如果要找的頁碼比半本書處的頁碼小,就書翻到四分之一處,否則,就把書翻到四分之三的地方。通過這種方法,你可以繼續把書分成更小的部分,直至找到正確的頁碼附近。這是找到書頁的非常有效的一種方法。
    SQL Sever的表索引以類似的方式工作。一個表索引由一組頁組成,這些頁構成了一個樹形結構。根頁通過指向另外兩個頁,把一個表的記錄從邏輯上分成和兩個部分。而根頁所指向的兩個頁又分別把記錄分割成更小的部分。每個頁都把記錄分成更小的分割,直至到達葉級頁。
        索引有兩種類型:聚簇索引和非聚簇索引。在聚簇索引中,索引樹的葉級頁包含實際的數據:記錄的索引順序與物理順序相同。在非聚簇索引中,葉級頁指向表中的記錄:記錄的物理順序與邏輯順序沒有必然的聯繫。
        聚簇索引非常象目錄表,目錄表的順序與實際的頁碼順序是一致的。非聚簇索引則更像書的標準索引表,索引表中的順序通常與實際的頁碼順序是不一致的。一本書也許有多個索引。例如,它也許同時有主題索引和作者索引。同樣,一個表可以有多個非聚簇索引。
        通常情況下,你使用的是聚簇索引,但是你應該對兩種類型索引的優缺點都有所理解。
        每個表只能有一個聚簇索引,因為一個表中的記錄只能以一種物理順序存放。通常你要對一個表按照標識字段建立聚簇索引。但是,你也可以對其它類型的字段建立聚簇索引,如字符型,數值型和日期時間型字段。
        從建立了聚簇索引的表中取出數據要比建立了非聚簇索引的表快。當你需要取出一定範圍內的數據時,用聚簇索引也比用非聚簇索引好。例如,假設你用一個表來記錄訪問者在你網點上的活動。如果你想取出在一定時間段內的登錄信息,你應該對這個表的DATETIME型字段建立聚簇索引。
        對聚簇索引的主要限制是每個表只能建立一個聚簇索引。但是,一個表可以有不止一個非聚簇索引。實際上,對每個表你最多可以建立249個非聚簇索引。你也可以對一個表同時建立聚簇索引和非聚簇索引。
        假如你不僅想根據日期,而且想根據用戶名從你的網點活動日誌中取數據。在這種情況下,同時建立一個聚簇索引和非聚簇索引是有效的。你可以對日期時間字段建立聚簇索引,對用戶名字段建立非聚簇索引。如果你發現你需要更多的索引方式,你可以增加更多的非聚簇索引。
        非聚簇索引需要大量的硬盤空間和內存。另外,雖然非聚簇索引可以提高從表中取數據的速度,它也會降低向表中插入和更新數據的速度。每當你改變了一個建立了非聚簇索引的表中的數據時,必須同時更新索引。因此你對一個表建立非聚簇索引時要慎重考慮。如果你預計一個表需要頻繁地更新數據,那麼不要對它建立太多非聚簇索引。另外,如果硬盤和內存空間有限,也應該限制使用非聚簇索引的數量。

    索引屬性
        這兩種類型的索引都有兩個重要屬性:你可以用兩者中任一種類型同時對多個字段建立索引(複合索引);兩種類型的索引都可以指定為唯一索引。
        你可以對多個字段建立一個複合索引,甚至是複合的聚簇索引。假如有一個表記錄了你的網點訪問者的姓和名字。如果你希望根據完整姓名從表中取數據,你需要建立一個同時對姓字段和名字字段進行的索引。這和分別對兩個字段建立單獨的索引是不同的。當你希望同時對不止一個字段進行查詢時,你應該建立一個對多個字段的索引。如果你希望對各個字段進行分別查詢,你應該對各字段建立獨立的索引。
        兩種類型的索引都可以被指定為唯一索引。如果對一個字段建立了唯一索引,你將不能向這個字段輸入重複的值。一個標識字段會自動成為唯一值字段,但你也可以對其它類型的字段建立唯一索引。假設你用一個表來保存你的網點的用戶密碼,你當然不希望兩個用戶有相同的密碼。通過強制一個字段成為唯一值字段,你可以防止這種情況的發生。

    用SQL建立索引
        為了給一個表建立索引,啟動任務欄SQL Sever程序組中的ISQL/w程序。進入查詢窗口後,輸入下面的語句:

            CREATE INDEX mycolumn_index ON mytable (myclumn)

        這個語句建立了一個名為mycolumn_index的索引。你可以給一個索引起任何名字,但你應該在索引名中包含所索引的字段名,這對你將來弄清楚建立該索引的意圖是有幫助的。
        注意:
        在本書中你執行任何SQL語句,都會收到如下的信息:
         This command did not return data,and it did not return any rows
    這說明該語句執行成功了。
    索引mycolumn_index對錶mytable的mycolumn字段進行。這是個非聚簇索引,也是個非唯一索引。 (這是一個索引的缺省屬性)
    如果你需要改變一個索引的類型,你必須刪除原來的索引並重建一個。建立了一個索引後,你可以用下面的SQL語句刪除它:

    DROP INDEX mytable.mycolumn_index

    注意在DROP INDEX語句中你要包含表的名字。在這個例子中,你刪除的索引是mycolumn_index,它是表mytable的索引。
    要建立一個聚簇索引,可以使用關鍵字CLUSTERED。 )記住一個表只能有一個聚簇索引。 (這裡有一個如何對一個表建立聚簇索引的例子:

    CREATE CLUSTERED INDEX mycolumn_clust_index ON mytable(mycolumn)

    如果表中有重複的記錄,當你試圖用這個語句建立索引時,會出現錯誤。但是有重複記錄的表也可以建立索引;你只要使用關鍵字ALLOW_DUP_ROW把這一點告訴SQL Sever即可:
     
    CREATE CLUSTERED INDEX mycolumn_cindex ON mytable(mycolumn)
                          WITH ALLOW_DUP_ROW

    這個語句建立了一個允許重複記錄的聚簇索引。你應該盡量避免在一個表中出現重複記錄,但是,如果已經出現了,你可以使用這種方法。
    要對一個表建立唯一索引,可以使用關鍵字UNIQUE。對聚簇索引和非聚簇索引都可以使用這個關鍵字。這裡有一個例子:

    CREATE UNIQUE COUSTERED INDEX myclumn_cindex ON mytable(mycolumn)

    這是你將經常使用的索引建立語句。無論何時,只要可以,你應該盡量對一個對一個表建立唯一聚簇索引來增強查詢操作。
    最後,要建立一個對多個字段的索引──複合索引──在索引建立語句中同時包含多個字段名。下面的例子對firstname和lastname兩個字段建立索引:

    CREATE INDEX name_index ON username(firstname,lastname)

    這個例子對兩個字段建立了單個索引。在一個複合索引中,你最多可以對16個字段進行索引。

    用事務管理器建立索引
    用事務管理器建立索引比用SQL語句容易的多。使用事務管理器,你可以看到已經建立的索引的列表,並可以通過圖形界面選擇索引選項。
    使用事務管理器你可以用兩種方式建立索引:使用Manage Tables窗口或使用Manage Indexes窗口。
        要用Manage Tables窗口建立一個新索引,單擊按鈕Advanced Options(它看起來像一個前面有一加號的表)。這樣就打開了Advanced Options對話框。這個對話框有一部分標名為Primary Key(見圖11.1)。
     
    圖11。1

    要建立一個新索引,從下拉列表中選擇你想對之建立索引的字段名。如果你想建立一個對多字段的索引,你可以選擇多個字段名。你還可以選擇索引是聚簇的還是非聚簇的。在保存表信息後,索引會自動被建立。在Manage Tables窗口中的字段名旁邊,會出現一把鑰匙。
    你已經為你的表建立了“主索引”。主索引必須對不包含空值的字段建立。另外,主索引強制一個字段成為唯一值字段。
    要建立沒有這些限制的索引,你需要使用Manage Indexes窗口。從菜單中選擇Manage|Indexes,打開Manage Indexes窗口。在Manage Indexes窗口中,你可以通過下拉框選擇表和特定的索引。 (見圖11.2)。要建立一個新索引,從Index下拉框中選擇New Index.,然後就可以選擇要對之建立索引的字段。單擊按鈕Add,把字段加人到索引中。

    圖11。2

    你可以為你的索引選擇許多不同的選項。例如,你可以選擇該索引是聚簇的還是非聚簇的。你還可以指定該索引為唯一索引。設計好索引後,單擊按鈕Build,建立該索引。

    注意:
    唯一索引是指該字段不能有重複的值,而不是只能建立這一個索引。

    SQL核心語句
    在第十章,你學會瞭如何用SQL SELECT語句從一個表中取數據。但是,到現在為止,還沒有討論如何添加,修改或刪除表中的數據。在這一節中,你將學習這些內容。

    插入數據
    向表中添加一個新記錄,你要使用SQL INSERT語句。這裡有一個如何使用這種語句的例子:

          INSERT mytable (mycolumn) VALUES (‘some data’)

    這個語句把字符串’some data’插入表mytable的mycolumn字段中。將要被插入數據的字段的名字在第一個括號中指定,實際的數據在第二個括號中給出。
    INSERT語句的完整句法如下:

    INSERT [INTO] {table_name|view_name} [(column_list)] {DEFAULT VALUES |
                     Values_list | select_statement}

    如果一個表有多個字段,通過把字段名和字段值用逗號隔開,你可以向所有的字段中插入數據。假設表mytable有三個字段first_column,second_column,和third_column。下面的INSERT語句添加了一條三個字段都有值的完整記錄:

    INSERT mytable (first_column,second_column,third_column)
             VALUES (‘some data’,’some more data’,’yet more data’)

    注意:
    你可以使用INSERT語句向文本型字段中插入數據。但是,如果你需要輸入很長的字符串,你應該使用WRITETEXT語句。這部分內容對本書來說太高級了,因此不加討論。要了解更多的信息,請參考Microsoft SQL Sever的文檔。

    如果你在INSERT語句中只指定兩個字段和數據會怎麼樣呢?換句話說,你向一個表中插入一條新記錄,但有一個字段沒有提供數據。在這種情況下,有下面的四種可能:
    ■如果該字段有一個缺省值,該值會被使用。例如,假設你插入新記錄時沒有給字段third_column提供數據,而這個字段有一個缺省值’some value’。在這種情況下,當新記錄建立時會插入值’some value’。
    ■如果該字段可以接受空值,而且沒有缺省值,則會被插入空值。
    ■如果該字段不能接受空值,而且沒有缺省值,就會出現錯誤。你會收到錯誤信息:
    The column in table mytable may not be null.
    ■最後,如果該字段是一個標識字段,那麼它會自動產生一個新值。當你向一個有標識字段的表中插入新記錄時,只要忽略該字段,標識字段會給自己賦一個新值。

        注意:
        向一個有標識字段的表中插入新記錄後,你可以用SQL變量@@identity來訪問新記錄
    的標識字段的值。考慮如下的SQL語句:

          INSERT mytable (first_column) VALUES(‘some value’)

          INSERT anothertable(another_first,another_second)
              VALUES(@@identity,’some value’)

        如果表mytable有一個標識字段,該字段的值會被插入表anothertable的another_first字段。這是因為變量@@identity總是保存最後一次插入標識字段的值。
    字段another_first應該與字段first_column有相同的數據類型。但是,字段another_first不能是應該標識字段。 Another_first字段用來保存字段first_column的值。

    刪除記錄
    要從表中刪除一個或多個記錄,需要使用SQL DELETE語句。你可以給DELETE語句提供WHERE子句。 WHERE子句用來選擇要刪除的記錄。例如,下面的這個DELETE語句只刪除字段first_column的值等於’Delete Me’的記錄:
     
    DELETE mytable WHERE first_column=’Deltet Me’

    DELETE語句的完整句法如下:

            DELETE [FROM] {table_name|view_name} [WHERE clause]

    在SQL SELECT語句中可以使用的任何條件都可以在DELECT語句的WHERE子句中使用。例如,下面的這個DELETE語句只刪除那些first_column字段的值為’goodbye’或second_column字段的值為’so long’的記錄:

    DELETE mytable WHERE first_column=’goodby’ OR second_column=’so long’

    如果你不給DELETE語句提供WHERE子句,表中的所有記錄都將被刪除。你不應該有這種想法。如果你想刪除應該表中的所有記錄,應使用第十章所講的TRUNCATE TABLE語句。

    注意:
    為什麼要用TRUNCATE TABLE語句代替DELETE語句?當你使用TRUNCATE TABLE語句時,記錄的刪除是不作記錄的。也就是說,這意味著TRUNCATE TABLE要比DELETE快得多。

    更新記錄
    要修改表中已經存在的一條或多條記錄,應使用SQL UPDATE語句。同DELETE語句一樣,UPDATE語句可以使用WHERE子句來選擇更新特定的記錄。請看這個例子:

    UPDATE mytable SET first_column=’Updated!’ WHERE second_column=’Update Me!’

    這個UPDATE語句更新所有second_column字段的值為’Update Me!’的記錄。對所有被選中的記錄,字段first_column的值被置為’Updated!’。
    下面是UPDATE語句的完整句法:

    UPDATE {table_name|view_name} SET [{table_name|view_name}]
            {column_list|variable_list|variable_and_column_list}
            [,{column_list2|variable_list2|variable_and_column_list2}…
             [,{column_listN|variable_listN|variable_and_column_listN}]]
             [WHERE clause]

    注意:
    你可以對文本型字段使用UPDATE語句。但是,如果你需要更新很長的字符串,應使用UPDATETEXT語句。這部分內容對本書來說太高級了,因此不加討論。要了解更多的信息,請參考Microsoft SQL Sever的文檔。

        
    如果你不提供WHERE子句,表中的所有記錄都將被更新。有時這是有用的。例如,如果你想把表titles中的所有書的價格加倍,你可以使用如下的UPDATE語句:
    你也可以同時更新多個字段。例如,下面的UPDATE語句同時更新first_column,second_column,和third_column這三個字段:

    UPDATE mytable SET first_column=’Updated!’
                          Second_column=’Updated!’
                          Third_column=’Updated!’
                      WHERE first_column=’Update Me1’

    技巧:
    SQL忽略語句中多餘的空格。你可以把SQL語句寫成任何你最容易讀的格式。

    用SELECT創建記錄和表
    你也許已經註意到,INSERT語句與DELETE語句和UPDATE語句有一點不同,它一次只操作一個記錄。然而,有一個方法可以使INSERT語句一次添加多個記錄。要作到這一點,你需要把INSERT語句與SELECT語句結合起來,像這樣:

    INSERT mytable (first_column,second_column)
    SELECT another_first,another_second
    FROM anothertable
    WHERE another_first=’Copy Me!’

    這個語句從anothertable拷貝記錄到mytable.只有表anothertable中字段another_first的值為’Copy Me! ’的記錄才被拷貝。
    當為一個表中的記錄建立備份時,這種形式的INSERT語句是非常有用的。在刪除一個表中的記錄之前,你可以先用這種方法把它們拷貝到另一個表中。
    如果你需要拷貝整個表,你可以使用SELECT INTO語句。例如,下面的語句創建了一個名為newtable的新表,該表包含表mytable的所有數據:
     
    SELECT * INTO newtable FROM mytable

    你也可以指定只有特定的字段被用來創建這個新表。要做到這一點,只需在字段列表中指定你想要拷貝的字段。另外,你可以使用WHERE子句來限制拷貝到新表中的記錄。下面的例子只拷貝字段second_columnd的值等於’Copy Me!’的記錄的first_column字段。
     
    SELECT first_column INTO newtable
    FROM mytable
    WHERE second_column=’Copy Me!’

    使用SQL修改已經建立的表是很困難的。例如,如果你向一個表中添加了一個字段,沒有容易的辦法來去除它。另外,如果你不小心把一個字段的數據類型給錯了,你將沒有辦法改變它。但是,使用本節中講述的SQL語句,你可以繞過這兩個問題。
    例如,假設你想從一個表中刪除一個字段。使用SELECT INTO語句,你可以創建該表的一個拷貝,但不包含要刪除的字段。這使你既刪除了該字段,又保留了不想刪除的數據。
    如果你想改變一個字段的數據類型,你可以創建一個包含正確數據類型字段的新表。創建好該表後,你就可以結合使用UPDATE語句和SELECT語句,把原來表中的所有數據拷貝到新表中。通過這種方法,你既可以修改表的結構,又能保存原有的數據。

    集合函數
    到現在為止,你只學習瞭如何根據特定的條件從表中取出一條或多條記錄。但是,假如你想對一個表中的記錄進行數據統計。例如,如果你想統計存儲在表中的一次民意測驗的投票結果。或者你想知道一個訪問者在你的站點上平均花費了多少時間。要對錶中的任何類型的數據進行統計,都需要使用集合函數。
    Microsoft SQL支持五種類型的集合函數。你可以統計記錄數目,平均值,最小值,最大值,或者求和。當你使用一個集合函數時,它只返回一個數,該數值代表這幾個統計值之一。

    注意:
    要在你的ASP網頁中使用集合函數的返回值,你需要給該值起一個名字。要作到這一點,你可以在SELECT語句中,在集合函數後面緊跟一個字段名,如下例所示:

    SELECT AVG(vote) ‘the_average’ FROM opinion

    在這個例子中,vote的平均值被命名為the_average。現在你可以在你的ASP網頁的數據庫方法中使用這個名字。

    統計字段值的數目
    函數COUNT()也許是最有用的集合函數。你可以用這個函數來統計一個表中有多少條記錄。這裡有一個例子:

    SELECT COUNT(au_lname) FROM authors

    這個例子計算表authors中名字(last name)的數目。如果相同的名字出現了不止一次,該名字將會被計算多次。如果你想知道名字為某個特定值的作者有多少個,你可以使用WHERE子句,如下例所示:

    SELECT COUNT(au_lname) FROM authors WHERE au_lname=’Ringer’

    這個例子返回名字為’Ringer’的作者的數目。如果這個名字在表authors中出現了兩次,則次函數的返回值是2。
    假如你想知道有不同名字的作者的數目。你可以通過使用關鍵字DISTINCT來得到該數目。如下例所示:

    SELECT COUNT(DISTINCT au_lname) FROM authors

    如果名字’Ringer’出現了不止一次,它將只被計算一次。關鍵字DISTINCT決定了只有互不相同的值才被計算。
    通常,當你使用COUNT()時,字段中的空值將被忽略。一般來說,這正是你所希望的。但是,如果你僅僅想知道表中記錄的數目,那麼你需要計算表中所有的記錄─不管它是否包含空值。下面是一個如何做到這一點的例子:

    SELECT COUNT(*) FROM authors

    注意函數COUNT()沒有指定任何字段。這個語句計算表中所有記錄所數目,包括有空值的記錄。因此,你不需要指定要被計算的特定字段。
    函數COUNT()在很多不同情況下是有用的。例如,假設有一個表保存了對你站點的質量進行民意調查的結果。這個表有一個名為vote的字段,該字段的值要么是0,要么是1。0表示反對票,1表示贊成票。要確定贊成票的數量,你可以所有下面的SELECT語句:

    SELECT COUNT(vote) FROM opinion_table WHERE vote=1

    計算字段的平均值
    使用函數COUNT(),你可以統計一個字段中有多少個值。但有時你需要計算這些值的平均值。使用函數AVG(),你可以返回一個字段中所有值的平均值。
    假如你對你的站點進行一次較為複雜的民意調查。訪問者可以在1到10之間投票,表示他們喜歡你站點的程度。你把投票結果保存在名為vote的INT型字段中。要計算你的用戶投票的平均值,你需要使用函數AVG():

    SELECT AVG(vote) FROM opinion

    這個SELECT語句的返回值代表用戶對你站點的平均喜歡程度。函數AVG()只能對數值型字段使用。這個函數在計算平均值時也忽略空值。

    計算字段值的和
    假設你的站點被用來出售卡片,已經運行了兩個月,是該計算賺了多少錢的時候了。假設有一個名為orders的表用來記錄所有訪問者的定購信息。要計算所有定購量的總和,你可以使用函數SUM():

    SELECT SUM(purchase_amount) FROM orders

    函數SUM()的返回值代表字段purchase_amount中所有值的平均值。字段purchase_amount的數據類型也許是MONEY型,但你也可以對其它數值型字段使用函數SUM()。

    返回最大值或最小值
    再一次假設你有一個表用來保存對你的站點進行民意調查的結果。訪問者可以選擇從1到10的值來表示他們對你站點的評價。如果你想知道訪問者對你站點的最高評價,你可以使用如下的語句:

    SELECT MAX(vote) FROM opinion

    你也許希望有人對你的站點給予了很高的評價。通過函數MAX(),你可以知道一個數值型字段的所有值中的最大值。如果有人對你的站點投了數字10,函數MAX()將返回該值。
    另一方面,假如你想知道訪問者對你站點的的最低評價,你可以使用函數MIN(),如下例所示:

    SELECT MIN(vote) FROM opinion

    函數MIN()返回一個字段的所有值中的最小值。如果字段是空的,函數MIN()返回空值。

    其它常用的SQL表達式,函數,和過程
    這一節將介紹一些其它的SQL技術。你將學習如何從表中取出數據,其某個字段的值處在一定的範圍,你還將學習如何把字段值從一種類型轉換成另一種類型,如何操作字符串和日期時間數據。最後,你將學會一個發送郵件的簡單方法。

    通過匹配一定範圍的值來取出數據
    假設你有一個表用來保存對你的站點進行民意調查的結果。現在你想向所有對你的站點的評價在7到10之間的訪問者發送書面的感謝信。要得到這些人的名字,你可以使用如下的SELECT語句:

    SELECT username FROM opinion WHERE vote>6 and vote<11

    這個SELECT語句會實現你的要求。你使用下面的SELECT語句也可以得到同樣的結果:

    SELECT username FROM opinion WHERE vote BETWEEN 7 AND 10

    這個SELECT語句與上一個語句是等價的。使用哪一種語句是編程風格的問題,但你會發現使用表達式BETWEEN的語句更易讀。
    現在假設你只想取出對你的站點投了1或者10的訪問者的名字。要從表opinion中取出這些名字,你可以使用如下的SELECT語句:

    SELECT username FROM opinion WHERE vote=1 or vote

       這個SELECT語句會返回正確的結果,沒有理由不使用它。但是,存在一種等價的方式。使用如下的SELECT可以得到相同的結果:

    SELECT username FROM opinion WHERE vote IN (1,10)

    注意表達式IN的使用。這個SELECT語句只取出vote的值等於括號中的值之一的記錄。
    你也可以使用IN來匹配字符數據。例如,假設你只想取出Bill Gates或President Clinton的投票值。你可以使用如下的SELECT語句:

    SELECT vote FROM opinion WHERE username IN (‘Bill Gates’,’President Clinton’)

    最後,你可以在使用BETWEEN或IN的同時使用表達式NOT。例如,要取出那些投票值不在7到10之間的人的名字,你可以使用如下的SELECT語句:

    SELECT username FROM opinion WHERE vote NOT BETWEEN 7 and 10

    要選取那些某個字段的值不在一列值之中的記錄,你可以同時使用NOT和IN,如下例所示:

    SELECT vote FROM opinion
                 WHERE username NOT IN (‘Bill Gates’,’President Clinton’)

    你不是必須在SQL語句中使用BETWEEN或IN,但是,要使你的查詢更接近自然語言,這兩個表達式是有幫助的。

    轉換數據
    SQL Sever足夠強大,可以在需要的時候把大部分數值從一種類型轉換為另一種類型。例如,要比較SMALLINT型和INT型數據的大小,你不需要進行顯式的類型轉換。 SQL Sever會為你完成這項工作。但是,當你想在字符型數據和其它類型的數據之間進行轉換時,你的確需要自己進行轉換操作。例如,假設你想從一個MONEY型字段中取出所有的值,並在結果後面加上字符串“US Dollars”。你需要使用函數CONVERT(),如下例所示:

    SELECT CONVERT(CHAR(8),price)+’US Dollars’ FROM orders

    函數CONVERT()帶有兩個變量。第一個變量指定了數據類型和長度。第二個變量指定了要進行轉換的字段。在這個例子中,字段price被轉換成長度為8個字符的CHAR型字段。字段price要被轉換成字符型,才可以在它後面連接上字符串’US Dollars’。
    當向BIT型,DATETIME型,INT型,或者NUMERIC型字段添加字符串時,你需要進行同樣的轉換操作。例如,下面的語句在一個SELECT語句的查詢結果中加入字符串’The vote is’,該SELECT語句返回一個BIT型字段的值:

    SELECT ‘The vote is’+CONVERT(CHAR(1),vote) FROM opinion

    下面是這個語句的結果示例:

    The vote is 1
    The vote is 1
    The vote is 0
    (3 row(s) affected)

    如果你不進行顯式的轉換,你會收到如下的錯誤信息:
    Implicit conversion from datatype ‘varchar’ to ‘bit’ is not allowec.
    Use the CONVERT function to run this query.

    操作字符串數據
    SQL Sever有許多函數和表達式,使你能對字符串進行有趣的操作,包括各種各樣的模式匹配和字符轉換。在這一節中,你將學習如何使用最重要的字符函數和表達式。

    匹配通配符
    假設你想建立一個與Yahoo功能相似的Internet目錄。你可以建立一個表用來保存一系列的站點名稱,統一資源定位器(URL),描述,和類別,並允許訪問者通過在HTML form中輸入關鍵字來檢索這些內容。
    假如有一個訪問者想從這個目錄中得到其描述中包含關鍵字trading card的站點的列表。要取出正確的站點列表,你也許試圖使用這樣的查詢:

    SELECT site_name FROM site_directory WHERE site_desc=’trading card’

    這個查詢可以工作。但是,它只能返回那些其描述中只有trading card這個字符串的站點。例如,一個描述為We have the greatest collection of trading cards in the world!的站點不會被返回。
    要把一個字符串與另一個字符串的一部分相匹配,你需要使用通配符。你使用通配符和關鍵字LIKE來實現模式匹配。下面的語句使用通配符和關鍵字LIKE重寫了上面的查詢,以返回所有正確站點的名字:
     
    SELECT SITE_name FROM site_directory
                      WHERE site_desc LIKE ‘%trading cark%’

        在這個例子中,所有其描述中包含表達式trading card的站點都被返回。描述為We have the greatest collection of trading cards in the world!的站點也被返回。當然,如果一個站點的描述中包含I am trading cardboard boxes online ,該站點的名字也被返回。
    注意本例中百分號的使用。百分號是通配符的例子之一。它代表0個或多個字符。通過把trading card括在百分號中,所有其中嵌有字符串trading card的字符串都被匹配。
    現在,假設你的站點目錄變得太大而不能在一頁中完全顯示。你決定把目錄分成兩部分。在第一頁,你想顯示所有首字母在A到M之間的站點。在第二頁,你想顯示所有首字母在N到Z之間的站點。要得到第一頁的站點列表,你可以使用如下的SQL語句:

    SELECT site_name FROM site_directory WHERE site_name LIKE ‘[AM]%’

    在這個例子中使用了表達式[AM],只取出那些首字母在A到M之間的站點。中括號([])用來匹配處在指定範圍內的單個字符。要得到第二頁中顯示的站點,應使用這個語句:

    SELECT site_name FROM site_directory
                      WHERE site_name LIKE ‘[N-Z]%’

    在這個例子中,括號中的表達式代表任何處在N到Z之間的單個字符。
    假設你的站點目錄變得更大了,你現在需要把目錄分成更多頁。如果你想顯示那些以A,B或C開頭的站點,你可以用下面的查詢來實現:
     
    SELECT site_name FROM site_directory WHERE site_name LIKE ‘[ABC]%’

    在這個例子中,括號中的表達式不再指定一個範圍,而是給出了一些字符。任何一個其名字以這些字符中的任一個開頭的站點都將被返回。
    通過在括號內的表達式中同時包含一個範圍和一些指定的字符,你可以把這兩種方法結合起來。例如,用下面的這個查詢,你可以取出那些首字母在C到F之間,或者以字母Y開頭的站點:

    SELECT site_name FROM site_directory WHERE site_name LIKE ‘[C-FY]%’

    在這個例子中,名字為Collegescape和Yahoo的站點會被選取,而名字為Magicw3的站點則不會被選取。
    你也可以使用脫字符(^)來排除特定的字符。例如,要得到那些名字不以Y開頭的站點,你可以使用如下的查詢:

    SELECT site_name FROM site_directory WHERE site_name LIKE ‘[^Y]%’

    對給定的字符或字符範圍均可以使用脫字符。
    最後,通過使用下劃線字符(_),你可以匹配任何單個字符。例如,下面這個查詢返回每一個其名字的第二個字符為任何字母的站點:

    SELECT site_name FROM site_directory WHERE site_name LIKE ‘M_crosoft’

    這個例子既返回名為Microsoft的站點,也返回名為Macrosoft的站點。但是,名字為Moocrosoft的站點則不被返回。與通配符’%’不同,下劃線只代表單個字符。

    注意:
    如果你想匹配百分號或下劃線字符本身,你需要把它們括在方括號中。如果你想匹配連字符(-),應把它指定為方括號中的第一個字符。如果你想匹配方括號,應把它們也括在方括號中。例如,下面的語句返回所有其描述中包含百分號的站點:

         SELECT site_name FROM site_directory WHERE site_desc LIKE ‘%[%]%’
    匹配發音
    Microsoft SQL有兩個允許你按照發音來匹配字符串的函數。函數SOUNDEX()給一個字符串分配一個音標碼,函數DIFFERENCE()按照發音比較兩個字符串。當你不知道一個名字的確切拼寫,但多少知道一點它的發音時,使用這兩個函數將有助於你取出該記錄。
    例如,如果你建立一個Internet目錄,你也許想增加一個選項,允許訪問者按照站點名的發音來搜索站點,而不是按名字的拼寫。考慮如下的語句:

    SELECT site_name FROM site_directory
                      WHERE DIFFERENCE(site_name , ‘Microsoft’>3

    這個語句使用函數DEFFERENCE()來取得其名字的發音與Microsoft非常相似的站點。函數DIFFERENCE()返回一個0到4之間的數字。如果該函數返回4,表示發音非常相近;如果該函數返回0,說明這兩個字符串的發音相差很大。
    例如,上面的語句將返回站點名Microsoft和Macrosoft。這兩個名字的發音與Microsoft都很相似。如果你把上一語句中的大於3改為大於2,那麼名為Zicrosoft和Megasoft的站點也將被返回。最後,如果你只需要差別等級大於1即可,則名為Picosoft和Minisoft的站點也將被匹配。
    要深入了解函數DIFFERENCE()是如何工作的,你可以用函數SOUNDEX()來返回函數DIFFERENCE()所使用的音標碼。這裡有一個例子:

    SELECT site_name ‘site name’,SOUNDEX(site_name) ‘sounds like’

    這個語句選取字段site_name的所有數據及其音標碼。下面是這個查詢的結果:

    site name sounds like
    ……………………………………………………………….
    Yahoo Y000
    Mahoo M000
    Microsoft M262
    Macrosoft M262
    Minisoft M521
    Microshoft M262
    Zicrosoft Z262
    Zaposoft Z121
    Millisoft M421
    Nanosoft N521
    Megasoft M221
    Picosoft P221
    (12 row(s) affected)

    如果你仔細看一下音標碼,你會注意到音標碼的第一個字母與字段值的第一個字母相同。例如,Yahoo和Mahoo的音標碼只有第一個字母不同。你還可以發現Microsoft和Macrosoft的音標碼完全相同。
    函數DIFFERENDE()比較兩個字符串的第一個字母和所有的輔音字母。該函數忽略任何元音字母(包括y),除非一個元音字母是一個字符串的第一個字母。
    不幸的是,使用SOUNDEX()和DIFFERENCE()有一個欠缺。 WHERE子句中包含這兩個函數的查詢執行起來效果不好。因此,你應該小心使用這兩個函數。

    刪除空格
    有兩個函數,TTRIM()和LTRIM(),可以用來從字符串中剪掉空格。函數LTRIM()去除應該字符串前面的所有空格;函數RTRIM()去除一個字符串尾部的所有空格。這裡有一個任何使用函數RTRIM()的例子:

    SELECT RTRIM(site_name) FROM site_directory

    在這個例子中,如果任何一個站點的名字尾部有多餘的空格,多餘的空格將從查詢結果中刪去。
    你可以嵌套使用這兩個函數,把一個字符串前後的空格同時刪去:

    SELECT LTRIM(RTRIM(site_name) FROM site_directory

    你會發現,在從CHAR型字段中剪掉多餘的空格時,這兩個函數非常有用。記住,如果你把一個字符串保存在CHAR型字段中,該字符串會被追加多餘的空格,以匹配該字段的長度。用這兩個函數,你可以去掉無用的空格,從而解決這個問題。

    操作日期和時間
    日期和時間函數對建立一個站點是非常有用的。站點的主人往往對一個表中的數據何時被更新感興趣。通過日期和時間函數,你可以在毫秒級跟踪一個表的改變。

    返回當前日期和時間
    通過函數GETDATE(),你可以獲得當前的日期和時間。例如,語句SELECT GETDATE()返回如下的結果:
    ……………………………..
         NOV 30 1997 3:29AM
    (1 row(s) affected)

    顯然,如果你將來使用這個函數,你得到的日期將比這個時間晚,或者梗早。
    函數GETDATE()可以用來作為DATEDIME()型字段的缺省值。這對插入記錄時保存當時的時間是有用的。例如,假設有一個表用來保存你站點上的活動日誌。每當有一個訪問者訪問到你的站點時,就在表中添加一條新記錄,記下訪問者的名字,活動,和進行訪問的時間。要建立一個表,其中的記錄包含有當前的日期和時間,可以添加一個DATETIME型字段,指定其缺省值為函數GETDATE()的返回值,就像這樣:

    CREATE TABLE site_log (
            username VARCHAR(40),
            useractivity VARCHAR(100),
            entrydate DATETIME DEFAULT GETDATE())

    轉換日期和時間
    你也許已經註意到,在上一節的例子中,函數GETDATE()的返回值在顯示時只顯示到秒。實際上,SQL Sever內部時間可以精確到毫秒級(確切地說,可以精確到3.33毫秒)。
    要得到不同格式的日期和時間,你需要使用函數CONVERT()。例如,當下面的這個語句執行時,顯示的時間將包括毫秒:

    SELECT CONVERT(VARCHAR(30),GETDATE(),9)

    注意例子中數字9的使用。這個數字指明了在顯示日期和時間時使用哪種日期和時間格式。當這個語句執行時,將顯示如下的日期和時間:
    …………………………………..
    Nov 30 1997 3:29:55:170AM
    (1 row(s) affected)

    在函數CONVERT()中你可以使用許多種不同風格的日期和時間格式。表11.1顯示了所有的格式。

    表11.1日期和時間的類型
    類型值標準輸出
        0 Default mon dd yyyy hh:miAM
        1 USA mm/dd/yy
        2 ANSI yy.mm.dd
        3 British/French dd/mm/yy
        4 German dd.mm.yy
        5 Italian dd-mm-yy
        6 – dd mon yy
        7 – mon dd,yy
        8 – hh:mi:ss
    9 Default + milliseconds–mon dd yyyy
    hh:mi:ss:mmmAM(or )
        10 USA mm-dd-yy
        11 JAPAN yy/mm/dd
        12 ISO yymmdd
        13 Europe Default + milliseconds–dd mon yyyy
                                            hh:mi:ss:mmm(24h)
        14 – hh:mi:ss:mmm(24h)

       類型0,9,和13總是返回四位的年。對其它類型,要顯示世紀,把style值加上100。類型13和14返回24小時時鐘的時間。類型0,7,和13返回的月份用三位字符表示(用Nov代表November).

    對錶11.1中所列的每一種格式,你可以把類型值加上100來顯示有世紀的年(例如,00年將顯示為2000年)。例如,要按日本標準顯示日期,包括世紀,你應使用如下的語句:

    SELECT CONVERT(VARCHAR(30),GETDATE(),111)

        在這個例子中,函數CONVERT()把日期格式進行轉換,顯示為1997/11/30

    抽取日期和時間
    在許多情況下,你也許只想得到日期和時間的一部分,而不是完整的日期和時間。例如,假設你想列出你的站點目錄中每個站點被查詢的月份。這時你不希望完整的日期和時間把網頁弄亂。為了抽取日期的特定部分,你可以使用函數DATEPART(),像這樣:

    SELECT site_name ‘Site Name’,
    DATEPART(mm,site_entrydate) ‘Month Posted’ FROM site_directory

    函數DATEPART()的參數是兩個變量。第一個變量指定要抽取日期的哪一部分;第二個變量是實際的數據。在這個例子中,函數DATEPART()抽取月份,因為mm代表月份。下面是這個SELECT語句的輸出結果:

    Site Name Month Posted
    ………………………………………………………………
    Yahoo 2
    Microsoft 5
    Magicw3 5
    (3 row(s) affected)

        Month Posted列顯示了每個站點被查詢的月份。函數DATEPART()的返回值是一個整數。你可以用這個函數抽取日期的各個不同部分,如表11.2所示。

    表11.2日期的各部分及其簡寫
    日期部分簡寫值
    year yy 1753–9999
    quarter qq 1–4
    month mm 1–12
    day of year dy 1–366
    day dd 1–31
    week wk 1–53
    weekday dw 1–7(Sunday–Saturday)
    hour hh 0–23
    minute mi 0–59
    second ss 0–59
    milisecond ms 0–999

    當你需要進行日期和時間的比較時,使用函數DATEPART()返回整數是有用的。但是,上例中的查詢結果(2,5)不是十分易讀。要以更易讀的格式得到部分的日期和時間,你可以使用函數DATENAME(),如下例所示:
     
    SELECT site_name ‘Site Name’
    DATENAME(mm,site_entrydate) ‘Month Posted’
    FROM site_directory

    函數DATENAME()和函數DATEPART()接收同樣的參數。但是,它的返回值是一個字符串,而不是一個整數。下面是上例該用DATENAME()得到的結果:

    Site Name Month Postec
    ………………………………………………………………….
    Yahoo February
    Microsoft June
    Magicw3 June
    (3 row(s) affected)

    你也可以用函數DATENAE()來抽取一個星期中的某一天。下面的這個例子同時抽取一周中的某一天和日期中的月份:

    SELECT site_name ‘Site Name’,
    DATENAME(dw,site_entrydate)+ ‘-’ + DATENAME(mm,site_entrydate)
              ‘Day and Month Posted’ FORM site_directory

    這個例子執行時,將返回如下的結果:

    Site Name Day and Month Posted
    ………………………………………………………………………
    Yahoo Friday – February
    Microsoft Tuesday – June
    Magicw3 Monday – June
    (3 row(s) affected)

    返回日期和時間範圍
    當你分析表中的數據時,你也許希望取出某個特定時間的數據。你也許對特定的某一天中――比如說2000年12月25日――訪問者在你站點上的活動感興趣。要取出這種類型的數據,你也許會試圖使用這樣的SELECT語句:

    SELECT * FROM weblog WHERE entrydate=”12/25/20000”

    不要這樣做。這個SELECT語句不會返回正確的記錄――它將只返回日期和時間是12/25/2000 12:00:00:000AM的記錄。換句話說,只有剛好在午夜零點輸入的記錄才被返回。

    注意:
    在本節的討論中,假設字段entrydate是DATETIME型,而不是SMALLDATETIME型。本節的討論對SMALLDATETIME型字段也是適用的,不過SMALLDATETIME型字段只能精確到秒。

    問題是SQL Sever將用完整的日期和時間代替部分日期和時間。例如,當你輸入一個日期,但不輸入時間時,SQL Sever將加上缺省的時間“12:00:00:000AM”。當你輸入一個時間,但不輸入日期時,SQL Sever將加上缺省的日期“Jan 1 1900”。
    要返回正確的記錄,你需要適用日期和時間範圍。有不止一種途徑可以做到這一點。例如,下面的這個SELECT語句將能返回正確的記錄:

    SELECT * FROM weblog
    WHERE entrydate>=”12/25/2000” AND entrydate<”12/26/2000”

    這個語句可以完成任務,因為它選取的是表中的日期和時間大於等於12/25/2000 12:00:00:000AM並小於12/26/2000 12:00:00:000AM的記錄。換句話說,它將正確地返回2000年聖誕節這一天輸入的每一條記錄。
    另一種方法是,你可以使用LIKE來返回正確的記錄。通過在日期表達式中包含通配符“%”,你可以匹配一個特定日期的所有時間。這裡有一個例子:

    SELECT * FROM weblog WHERE entrydate LIKE ‘Dec 25 2000%’

    這個語句可以匹配正確的記錄。因為通配符“%”代表了任何時間。
    使用這兩種匹配日期和時間範圍的函數,你可以選擇某個月,某一天,某一年,某個小時,某一分鐘,某一秒,甚至某一毫秒內輸入的記錄。但是,如果你使用LIKE來匹配秒或毫秒,你首先需要使用函數CONVERT()把日期和時間轉換為更精確的格式(參見前面“轉換日期和時間”一節)。

    比較日期和時間
    最後,還有兩個日期和時間函數對根據日期和時間取出記錄是有用的。使用函數DATEADD()和DATEDIFF(),你可以比較日期的早晚。例如,下面的SELECT語句將顯示表中的每一條記錄已經輸入了多少個小時:

    SELECT entrydate ‘Time Entered’
    DATEDIFF(hh,entrydate,GETDATE()) ‘Hours Ago’ FROM weblog

    如果當前時間是2000年11月30號下午6點15分,則會返回如下的結果:

    Time Entered Hours Ago
    …………………………………………………..
    Dec 30 2000 4:09PM 2
    Dec 30 2000 4:13PM 2
    Dec 1 2000 4:09PM 698
    (3 row(s) affected)

    函數DADEDIFF()的參數是三個變量。第個變量指定日期的某一部分。在這個例子中,是按小時對日期進行比較,(要了解日期各部分的詳細內容,請參考表11.2)在日期2000年11月1日和2000年11月30日的指定時間之間有689個小時。另外兩個參數是要進行比較的時間。為了返回一個正數,較早的時間應該先給。
    函數DATEADD()把兩個日期相加。當你需要計算截止日期這一類的數據時,這個函數是有用處的。例如,假設訪問者必須先註冊才能使用你的站點。註冊以後,他們可以免費使用你的站點一個月。要確定什麼時候他們的免費時間會用完,你可以使用如下的SELECT語句:

    SELECT username ‘User Name’,
    DATEADD(mm,1,firstvisit_date) ‘Registration Expires’
    FROM registration_table

    函數DATEADD()的參數有三個變量。第一個變量代表日期的某一部分(參見表11.2),這個例子用到了代表月份的mm。第二個變量指定了時間的間隔――在本例中是一個月。最後一個變量是一個日期,在這個例子中,日期是取自DATETIME型字段firstvisit_date.假設當前日期是June 30,2000,這個語句將返回如下的內容:

    User Name Registration Expires
    ……………………………………………………………………………
    Bill Gates Jul 30 2000 4:09PM
    President Clinton Jul 30 2000 4:13PM
    William Shakespeare Jul 1 2000 4:09PM
    (3 row(s) affected)

    注意:
    與你預料的相反,使用函數DATEADD()把一個日期加上一個月,它並不加上30天。這個函數只簡單地把月份值加1。這意味著在11月註冊的人將比在2月註冊的人多得到2天或3天的時間。要避免這個問題,你可以用函數DATEADD()直接增加天數,而不是月份。

    發送郵件
    你可以用SQL Sever發送簡單的e_mail信息。要做到這一點,你需要在你的系統中安裝郵件服務器,如Microsoft Exchange Sever(參見第四章“Exchange Active Sever,Index Sever,和NetShow”)。你還需要配置SQL Sever以識別郵件服務器。
    要讓SQL Sever能識別郵件服務器,啟動事務管理器並從菜單中選擇Sever|SQL Mail|Configue,這時會出現一個如圖11.3所示的對話框。輸入你在郵件服務器中註冊的用戶名和口令,然後單擊OK。

    注意:
    如果你使用Microsoft Exchange Sever,配置SQL Sever的過程將會大大不同。你需要在同一個(域)用戶帳號下運行Microsoft SQL Sever和Exchange Sever。你還需要在安裝了SQL Sever的機器上安裝Exchange Cliect並給這個帳號創建一個一個配置文件。完成這些之後,你就可以在SQL Mail Configuration對話框中輸入該配置文件的名字。
     
    圖11。3

    在發送郵件之前,你要先啟動SQL Mail。從菜單中選擇Sever|SQL Mail|Start。如果你的郵件服務器配置正確,並且你輸入了正確的用戶名和口令,則SQL Mail會成功啟動。

    注意:
    你可以把SQL Sever配置為自動啟動郵件服務。要做到這一點,在Set Sever Optons對話框(從菜單中選擇Sever|SQL Sever|Configure)中選擇Auto Start Mail Client即可。

    要發送一個郵件,你可以使用名為xp_sendmail的擴展存儲過程。這裡有一個如何使用這個過程的例子:

    master..xp_sendmail “president@whitehouse.gov”,”Hello Mr. President”

    這個過程調用向e_mail地址president@whitehouse.gov發送一個簡單的email信息:“Hello Mr. President”。你可以用任何其它的email地址和信息取代上例中相應的內容,但是,你所發送的信息不能超過255個字符長度。
        當你想隨時了解你的站點數據庫的狀態時,存儲過程xp_sendmail是有用處的。例如,你可以向一個頁面管理程序發送信息。如果你的站點出了什麼問題,你馬上就可以知道。下一章將講述更多有關存儲過程的內容。

    總結
    這一章加深了你的SQL知識。你學會瞭如何建立索引,使你的查詢速度更快。你還學會瞭如何插入,刪除和更新一個表中的數據,如何使用集合函數得到一個表中數據的統計信息。最後,你學會了許多有價值的表達式,函數和過程,用來操作字符串,日期和時間及郵件。
    下一章將進一步加深你對Microsoft SQL Sever的掌握。你將學習如何用SQL來進行程序設計,如何建立存儲過程,觸發器和執行計劃。更另人興奮的是,你將學會讓SQL Sever自動創建網頁的一個簡單方法。

  • Linux認證:為何SAP與Oracle排斥Ubuntu?

    雖然Canonical公司不斷增加Ubuntu的合作夥伴,但至少有兩個重要的軟件供應商仍然不支持Ubuntu Linux 。

    資料:

    Kubuntu與Xubuntu是Ubuntu計劃正式支援的衍生版本,分別將KDE與Xfce桌面環境帶入Ubuntu,Edubuntu是一個針對學校教學環境而設計,試圖讓低齡兒童可以輕鬆學會使用的衍生版本。

    Ubuntu建基於Debian的不穩定分支:不論其軟件格式(deb)還是軟件管理與安裝系統(Debian Apt/Synaptic)。 Ubuntu的開發者會把對軟件的修改及時反饋給Debian社群,而不是在發布新版時才宣布這些修改。事實上,很多Ubuntu的開發者同時也是Debian主要軟件的維護者。不過,Debian與Ubuntu的軟件並不一定完全兼容,也就是說,將Debian的軟件包安裝在Ubuntu上可能會出現兼容性問題,反之亦然。

    Ubuntu的運作主要依靠Canonical有限公司的支持,同時亦有來自Linux社區的熱心人士提供協助。 Ubuntu的開發人員多稱馬克?舍特爾沃斯為SABDFL(是self-appointed benevolent dictator for life的縮寫,即自封的項目決策者)。在2005年7月8日,馬克?舍特爾沃斯與Canonical有限公司宣布成立Ubuntu基金會,並提供1千萬美元作為啟始營運資金。成立基金會的目的是為了確保將來Ubuntu得以持續開發與獲得支持,但直至2006年,此基金會仍未投入運作。馬克?舍特爾沃斯形容此基金會是在Canonical有限公司出現財務危機時的緊急營運資金。

    目前,Ubuntu的最新長期支持版本為‘Hardy Heron’,即在2008年4月24日所推出Ubuntu 8.04 LTS(長期支持版),使用者可以透過船運服務(shipit)來獲得免費的安裝光碟。前一個LTS版本(Ubuntu 6.06)也有提供免費船運服務,然而其後的Ubuntu 6.10版卻沒有提供免費的船運郵寄光碟服務,使用者只可由網站上下載光碟映像檔燒錄並安裝。 Ubuntu 6.06釋出當時曾有消息指出往後不會再對非長期支持版提供船運服務,但在Ubuntu7.04版推出時,船運服務再度啟動,而此版並非長期支持版。

    已於2008年4月發布的Ubuntu 8.04和6.06一樣,都有著Long Term Support (LTS)的標籤,代表著這個版本也將獲得更長時間的技術支援(Desktop版3年,Server版5年)。

    Ubuntu急於爭取Oracle支持

    Linux廠商Canonical正在努力為Ubuntu Linux發行版,獲得更多的軟件和硬件認證。在其最新一輪的合作夥伴關係中,Canonical正在擴大其與IBM,Alfresco, Zimbra,Likewise, Centrify等之間的合作關係。

    然而雖然Canonical展示了努力擴大其聯盟的勢頭,但至少有兩家知名的公司不在Ubuntu的合作夥伴關係中。目前Oracle公司和SAP公司都不支持Ubuntu,並且都沒有想要立即合作的計劃。並且Linux系統上的競爭對手Red Hat公司和Novell公司都得到Oracle和SAP的認證,它們有可能將Ubuntu排除在Linux的部署之外。

    Canonical的ISV合作聯盟經理的Malcolm Yates在internetnews.com上聲稱: “Oracle and SAP是我們繼續致力於爭取的兩個大的軟件合作商。他們都有不一定要轉移到Ubuntu的原因。從ISV舊的案例告訴我們,轉移到另一OS的供應商有可能要重新分配我們已具備資源,我們為什麼要轉移到另一OS的供應商,而且我們必須要重新培訓我們所有的人員。”

    Oracle在1998年對Linux的支持,一直被專家認為是Linux在操作系統市場上成功的最關鍵原因之一。 Ubuntu在過去的四年裡的已獲得了使用者的認可,經常在Linux發行版情報網站distrowatch和其它地方人氣高居榜首。儘管其有這種明顯的人氣,但Oracle還是對Ubuntu不太感興趣。

    “Oracle公司目前尚無支持Ubuntu Linux的計劃, ”一位Oracle發言人在發向internetnews.com的一封電子郵件中寫到。 “Oracle的支持的發行版是Novell的SLES , Red Hat的RHEL ,Asianux和Oracle Enterprise Linux 。這些決定是基於客戶的需求以及Oracle在Linux系統應用開發上的重心” 。 Oracle Enterprise Linux是Oracle發行的自己的Linux版本,它是基於Red Hat Enterprise Linux系統。今年早些時候,Oracle聲稱,它的Linux版本已有超過2000個客戶。因此安裝Oracle Linux的收入至少是5億美元。

    Yates稱:“我們之前已經和他們(Oracle)談過了,我認為Oracle和大多數獨立軟件開發商是不同的,因為他們有自己的Linux ,我認為相比較讓他們開始出售Ubuntu,比出售自己的Linux更困難。”他補充說,他很想取得Oracle公司的支持,但短期內還沒有這個打算。

    SAP堅持他的決定

    SAP公司,雖然並沒有自己的Linux,但目前它也不打算支持Ubuntu。

    “ SAP公司支持Red Hat Enterprise Linux和Novell SUSE Linux Enterprise Server , ” SAP的行業標準副主席Michael Bechauf,告訴internetnews.com 。 “在這個時候,我們是回應客戶在企業空間的需求,將決定我們支持相應的戰略” 。

    雖然目前Oracle和SAP還不支持者Ubuntu, IBM公司,作為企業軟件的支柱,自2005年以來就一直支持Ubuntu。然而IBM公司的支持並不全面,起初只是對DB2數據庫產品的認證。上週, IBM和Canonical的合作夥伴關係擴大到包括IBM Lotus Symphony辦公軟件,IBM Lotus Symphony是“不用微軟”(Microsoft-free)計劃的一部分。然而,IBM與Ubuntu的伙伴關係,並沒有到達IBM與Red Hat以及Novell的合作水平。

    “我們與Ubuntu合作的重點是Ubuntu正在牽引我們發展的領域, ” IBM的Linux主任Inna Kuznetsova,告訴internetnews.com 。 “至於其他地區,我們將不斷探討,因為他們也在逐漸成長。我們與Red Hat和Novell的合作關係是非常穩健的,包括所有IBM服務器線路和支持數量龐大的IBM中間件產品” 。

    從網絡資源內容管理軟件開發商Alfresco的數據來看,越來越多的人在使用Ubuntu系統。從其最近的開放源代碼的統計來看,該公司報告說, 23 %的用戶使用Ubuntu系統, 35 %的用戶使用Red Hat Linux。

    Ubuntu逐漸得到更廣泛的接受, Yates很清楚Canonical公司下一步需要做什麼。 Canonical公司將致力於使製造商安裝使用Ubuntu系統,並繼續建立一個合作夥伴系統。 Canonical為Dell電腦提供預安裝Ubuntu系統,特惠商品的貨架上也開始出售Ubuntu系統。 Yates稱: “它的所有有關的認證和系統建設,正是我們一直在努力方向,合作夥伴和適用的應用軟件是成功的關鍵。作為應用軟件,我們將一直致力於應用軟件的開發” 。

    雖然Oracle和SAP目前不支持Ubuntu的,但還是有很多其他廠商支持。 Yates聲稱: “有越來越多的機會在那裡,我們公司還在不斷的成長” 。

  • 從C++轉到Java需注意的地方

    1.Java在虛擬機上運行
    Java源代碼並不是被編譯成為普通的機器代碼。而是被翻譯成為虛擬機可以執行的代碼。一個Java解釋器最終執行這些代碼。這其中沒有連接的過程;解釋在需要的時候動態的加載一些類;

    2.Java是完全面向對象的

    Java是一種完全面向對象的語言。這意味著你對任何一個Java對象所做的動作都是通過一個方法實現的。第一點就是,再也沒有沒有主函數這樣的孤立的東西了。取而代之的是,你必須開始用一個對象的看法看待一個程序,一個類的對象。但是這個對象又什麼對象呢?大多數Java程序只是簡單的通過繼承Java基礎類Object來實現所需要的東西,但是你可以通過創建程序基礎類用於多個特性相似的應用程序來節省時間。

    嚴格的面向對象的規定意味著理用原有的C/C++代碼不可以直接不加改動的使用;系統調用也是這樣的。 C++中,你可以通過在C++正常的命名空間外聲明extern”C”來使用原有的C的過程調用,包括系統調用

    在Java中,只有一個類似的安全回溯的方法,但是並不是十分簡單的方法。你必須定義一個本地方法,其目的是為C語言提供接口,然後提供連接的介質。 Java環境提供了完成這種任務的工具,但是整個過程和C++中提供的extern比微不足道,完成使用C++類的過程則更加複雜,因為這樣會引入對C的藉口和C函數和C++成員函數的問題。

    幸運的是,許多常用的系統實用工具函數已經在系統類中的方法中提供出來,但是這些明顯沒有包含經過許多年來你所創建的那些類和過程。所以,在你需要的時候你應該去鑽研一下。

    3.Java中沒有獨立的頭文件

    在Java中,關於類的一切東西都被放到一個單獨的文件中。方法的位置只可能在一個地方出現,一個方法的實現必須在它的定義過程中同時進行。這樣做得優點是在實現程序的時候不容易因為文件的非同步錯誤而失敗,或者獲取到一個沒有實現的聲明。類的聲明可以被Java解釋器利用甚至是從一個編譯過的單元中獲取,所以不再需要有頭文件,只要有編譯過的文件。

    這樣做的缺點與我們編程的過程有關。許多C++程序員喜歡用頭文件來代替文檔。要看一個成員函數的接口參數,只需要看頭文件中的聲明即可。你可以經常的看頭文件即可了解怎樣去使用這個類。在Java中,沒有這樣的總結。因為實現類方法的代碼必須在方法定義的時候出現,而且,對於一個單獨的函數的代碼來說就經常佔據了一整頁乃至更多。這樣,很難通過看Java的代碼就初步了解類是怎樣使用的。你必須為你需要的類準備足夠多的文檔。不言而喻,再處理非商業類庫的時候文檔是極度缺乏的。

    在當先的Java環境中提供了兩個工具來補償這些,javap來打印類標識,javadoc為嵌入式程序提供HTML文檔。

    4.用Package來分解Java命名空間

    在大的C++工程中經常遇到的一個問題是命名空間–怎樣保證工程的一些程序員不會創建和另一些程序員一樣名字的類?更糟糕的是,供應商可能會提供一個包含和你的類一樣名字的類的庫。有許多方法可以解決這一問題,但是很可能在問題發現之前工程已經啟動,改正錯誤是需要付出許多痛苦的。

    Java通過”Package”這個概念解決了這個問題,Package有效地通過通過集合類劃分了命名空間。在不同包內的兩個同名的類仍然是不同的。關鍵問題就變成了類是否放置到相應的包中。

    記住,Java並沒有解決命名衝突的問題。擴展一個基類而引起了派生類的衝突。比如說,如果你最喜歡的供應商提供了一些類,然後你把它們用做基類並且派生有一個foo方法的類,當供應商提供一個新版本的類的時候就可能出現,如果供應商業也在新類中提供了一個foo的方法。

    5.異常是Java的重要特性

    在C++中,異常和異常處理是十分深奧的事情;許多C++程序員從沒有處理過它們甚至不知道它們是何物。異常是在正常的過程中出現的未預料的錯誤,因此,它們不會從方法中返回,或者作為參數傳入;但是,它們不能被忽略!這裡的一個例子是計算一個書的方根的方法。正常的接口形式是將一個正數作為參數傳入方法,然後方法會返回一個正實數作為結果,方法可以檢驗這些並且在異常產生的時候拋出異常。在大多數係統中,程序員並不是必須這樣做,這樣,一個沒有考慮到的異常可以使程序不正常的退出。

    在Java中,異常已經成為語言中非常成熟的部分。方法的說明中就包含了異常的信息,程序處理器也強制檢驗如果你使用了一個能夠產生異常的方法,你就必須檢查異常是否發生。幾乎所有的Java程序員都會遇到異常的情況,因為許多非常有用的庫中的類都會拋出異常。處理異常並不難,但是在一些時候是需要注意的。一個方法的文檔會指明方法拋出的異常的類型。如果你忘了,不要緊,編譯器會提醒你的。
      
    6.字符串不再是字符數組

    Java中包括了一個字符串的對象,並且是個常量。字符串不像字符數組一樣,雖然可以簡單的從一個字符數組構造一個字符串。你應該盡可能的用字符串代替字符數組,因為他們不會因為誤操作而被覆蓋。

    7.Java限制了常量對象和方法

    在C++中,你可以正式的聲明一個函數參數或者函數返回值為const類型,這樣可以有效的防止對參數或者返回值的不正當修改。另外,你可以聲明一個成員函數為const,表明它不可以修改任何他操作的對象。

    Java支持常量操作符,只讀變量,這些通過final關鍵字實現。但是Java沒有支持強制的使一個可寫變量在函數傳遞、返回的過程中變為只讀。或者定義一個不操作修改對象的常量方法。

    在Java中,這個省略帶來的影響和在C++中相比就非常小了,這很大程度上因為字符串變量和字符數組的不同,但是這也帶來一個引起錯誤的隱患。特別地,沒有辦法檢驗一個方法是否可以改動對象。

    8.Java沒有指針

    理解指針的概念是一個C或C++程序員最難應付的問題。指針也是錯誤產生的一大根源。 Java中沒有指針,對象的句柄直接作為參數傳遞,而不是傳遞指針。另外,你必須通過索引使用數組。這些都不是什麼大問題。然而,沒有指針是在寫含有函數指針或者成員函數指針的系統的時候引起很大麻煩。這個問題在處理回調函數的時候更加顯著。

    9.Java沒有參數化類型

    參數化類型提供了用一段程序處理許多相似程序的方法。一個例子就是開平方根的方法,它可以對int或者float操作。在C++中,這一特性是由模板提供的。

    Java中不包含C++中的模板的等價物。如果你經常使用模板來簡化程序,比如說構造許多使用相似參數類型的函數,這簡直就是災難。這意味著更多使用複制、粘貼的過程來手動的完成。然而,如果你使用模板來生成類的話,沒有簡單的方法。

    10.Java使用垃圾回收

    在垃圾回收的語言中,運行時環境一直監測哪些內存不被使用。當一塊內存不用的時候,系統自動的回收內存。比如說,一個對像在一個方法中生成,但是沒有被調用著返回或者沒有儲存為全局變量,不能在方法外部使用。系統自己會知道哪些變量是你用不到的,哪些是可以用到的。因此,你不必再為破壞對象回收內存而擔心。在C++中,很多的調試時間都被使用到檢查內存漏洞中。 Java的這種方法很大程度上降低了這種錯誤的可能。但是他依然不能處理邏輯混亂的程序,他們不能夠被回收。許多C++的類中的析構函數是用來釋放對象引用的內存的。 Java使垃圾回收的事實說明在Java中不是必需寫析構函數了。但是並不意味著你可以忘記為你的類寫析構函數。比如,一個對像打開了網絡連接就必須被恰當的清理來關閉這個連接。在Java中,析構函數被稱作”finalization”方法。

    11.Java不支持多重繼承

    在任何一個複雜的面向對象的系統中,實現一個有更多方法的新類是十分經常遇到的事情。比如說,一個Manager類,需要被作為一個連表的表頭,但是一個Manager又必須是一個Employee。有許多方法來處理這樣的問題。一個方法是允許從多個類繼承。在這個例子中,Manager需要從Linked List和Employee繼承。

    Java沒有多重繼承。但是你可以聲明接口–來描述實現一些功能的編程接口。一個類可以由多個接口實現,包括他唯一的功能。不同的類可以由同樣的接口實現。方法的參數既可以聲明為類,也可以聲明為接口。如果是接口的話,實現接口的類就可以作為參數傳入方法。

    接口的概念要比多繼承容易理解一些,但是他有一定的局限性。特別地,你必須在類中實現接口的時候編碼去重新實現類的功能。

    12.Java支持多線程

    多線程可以使你寫出在同一時刻完成多種任務的程序。比如說,你可以在完成讀取一個大文件之間允許用戶對已經讀取的部分進行編輯。你需要把程序分為多線程來執行。為安全起見。你的程序要被精心的設計,因為可能不止一個線程需要對數據進行訪問、修改。

    Java開始就支持多線程。類和接口用來分解一個程序成為不同的線程。語言簡單的對重要的數據作同步或者鎖定處理。

    13.Java以一些預定義的類為基礎

    默認的Java環境中包括一些從Java基礎類實現而來的一些包。這些允許你很快的寫出一些有用的程序,這些包如下:

    java.awt:當今許多應用程序都非常依賴GUI,java提供了一個Abstract Window Toolkid,這可以讓你在不考慮運行平台的前提下處理GUI對象。

    java.applet:applet的主要目的是提供瀏覽有關的內容。它本身是awt組件的字類並且支持其他一些特性,比如聲音、渲染等。
      
    java.io:java.io提供了對流、文件、管道的讀寫操作。

    java.lang:提供了java的基礎類Objcet,Integar,Float……;

    java.net:提供對網絡編程的支持。包括處理socket,URL,Internet尋址等。

    java.util:為數據結構提供的通用實用工具集

  • Cisco最近公佈了一項新的專家級網絡設計認證——CCDE

    CCDE 專家級網絡設計認證

     思科網站原文:

    Program Updates – 1/22/08
    Cisco Announces New “Expert” Network Design Certification Program
    Cisco is announcing an expansion of its Network Design certification track to include a Network Design Expert designation,

    the Cisco Certified Design Expert (CCDE). The CCDE certification is a certification that identifies those with expert-

    level knowledge and skills in Infrastructure Design. CCDE is parallel to CCIE in terms of difficulty, and expertise. It

    emphasizes network design principles and theory at the Layer 3 level or Routing layer and recognizes expertise of

    designers that have the knowledge to assess network business requirements and can translate them into technical

    specifications to be incorporated into successful designs.

    The new Expert program is modeled after the industry leading CCIE program with a “qualification” and subsequent

    “practical” exam. Currently, the qualification exam is available worldwide at any Pearson VUE testing center. The

    practical exam is still in development and is expected to be released later this year.

    For more information visit the CCDE page

    來源:www.itcert.org

  • 華為認證:華為新命令行解析

    劃分命令級別

    過去:

    原來也有用戶命令級別映射功能,只使用了0、1、15級別,基本上大部分命令都是15級,進入特權模式後可以使用系統的所有命令.

    現在:

    命令劃分了4個級別,與用戶級別一一對應不同級別用戶僅可以使用相同或更低級別命令用戶登錄後,級別通常不會發生變化.

    過去:

    用戶登錄後進入普通用戶模式

    Quidway>enable 15進入特權模式,同時級別切換為15

    Quidway#configure terminal進入全局配置模式

    Quidway(config)#在全局模式下

    Quidway(config)#interface Ethernet 6/0/0進入接口模式

    Quidway(config-if-Ethernet6/0/0)#在接口模式下

    Quidway(config)#router bgp 1進入路由配置模式

    Quidway(config-router-bgp)#在路由配置模式下

    現在:

    用戶登錄後,進入用戶視圖

    super 3切換用戶級別為3,視圖不變

    在用戶視圖下

    system-view進入系統視圖

    [Quidway]在系統視圖下

    [Quidway]interface Ethernet 6/0/0進入接口視圖

    [Quidway-Ethernet6/0/0]在接口視圖下

    [Quidway]bgp 1進入BGP視圖

    [Quidway-bgp]在BGP視圖下

    統一用戶視圖

    1、參觀級:網絡診斷工具命令(PING、TRACERT)、從本設備出發訪問外部設備的命令(包括:TELNET客戶端、SSH客戶端、RLOGIN)等,隱藏命令。該級別命令不允許進入配置文件保存

    2、監控級:用於系統維護、業務故障診斷等,包括:DISPLAY命令、DEBUGGING命令,該級別命令不允許進入配置文件保存

    3、配置級:業務配置命令,包括:路由、各個網絡層次的命令,這些用於向用戶提供直接網絡服務的命令

    4、管理級:關係到系統基本運行,系統支撐模塊的命令,這些命令對業務提供起到支撐作用,包括:文件系統、FTP、TFTP、XMODEM下載、配置文件切換命令、電源控制命令、備板控制命令、用戶管理命令、級別設置命令、系統內部參數設置命令

    (非協議規定、非RFC規定等)

    過去:

    用戶首先進入普通配置模式,用戶進入系統後為缺省為最低級別,用戶使用enable命令進入特權模式,並提升級別為最高級
    現在:

    取消特權模式,用戶首先進入用戶視圖,每一個用戶有一個級別,登錄後如果不使用super命令,級別不會發生變化,CONSOLE口登錄,缺省級別為最高級

    過去:

    Quidway>普通配置模式

    Quidway#特權配置模式

    Quidway(config)#全局配置模式

    Quidway(config-if-Ethernet6/0/0)#接口配置模式

    Quidway(config-router-bgp)# BGP路由配置模式

    現在:

    用戶視圖

    [Quidway]系統視圖

    [Quidway-Ethernet6/0/0]接口視圖

    [Quidway-bgp] BGP視圖

    命令視圖

    與原來的命令模式概念對應,原來的訪問模式和特權模式統一為用戶視圖,配置模式對應系統視圖命令空間不同級別用戶,對應不同命令空間,可訪問命令範圍不同

    普通配置模式用戶視圖

    特權配置模式

    全局配置模式系統視圖

    接口配置模式接口視圖

    BGP路由配置模式BGP視圖

  • 如何加強Linux操作系統安全的配置說明

    眾所周知,網絡安全是一個非常重要的課題,而服務器是網絡安全中最關鍵的環節。 Linux被認為是一個比較安全的Internet服務器,作為一種開放源代碼操作系統,一旦Linux系統中發現有安全漏洞,Internet上來自世界各地的志願者會踴躍修補它。然而,系統管理員往往不能及時地得到信息並進行更正,這就給黑客以可乘之機。相對於這些系統本身的安全漏洞,更多的安全問題是由不當的配置造成的,可以通過適當的配置來防止。下面就簡單列出以下幾點,以供大家參考:

    1、用防火牆關閉不須要的任何端口,別人PING不到服務器,威脅自然減少了一大半

    防止別人ping的方法:

    1)命令提示符下打

    echo 1> /proc/sys/net/ipv4/icmp_ignore_all

    2)用防火牆禁止(或丟棄)icmp包

    iptables -A INPUT -p icmp -j DROP

    3)對所有用ICMP通訊的包不予響應

    比如PING TRACERT

    2、更改SSH端口,最好改為10000以上,別人掃描到端口的機率也會下降

    vi /etc/ssh/sshd_config

    將PORT改為1000以上端口

    同時,創建一個普通登錄用戶,並取消直接root登錄

    useradd ‘username’

    passwd ‘username’

    vi /etc/ssh/sshd_config

    在最後添加如下一句:

    PermitRootLogin no #取消root直接遠程登錄

    3、刪除系統臃腫多餘的賬號: userdel adm userdel lp userdel sync userdel shutdown userdel halt userdel news userdel uucp userdel operator userdel games userdel gopher userdel ftp如果你不允許匿名FTP,就刪掉這個用戶帳號groupdel adm groupdel lp groupdel news groupdel uucp groupdel games groupdel dip groupdel pppusers

    4、更改下列文件權限,使任何人沒有更改賬戶權限: chattr +i /etc/passwd chattr +i /etc/shadow chattr +i /etc/group chattr +i /etc/gshadow

    5、chmod 600 /etc/xinetd.conf

    6、關閉FTP匿名用戶登陸

  • Linux資格認證考試綜合輔導:備份與壓縮命令

    用戶經常需要備份計算機系統中的數據,為了節省存儲空間,常常將備份文件進行壓縮。下面分別介紹備份與壓縮的命令。

    tar命令

    tar可以為文件和目錄創建檔案。利用tar,用戶可以為某一特定文件創建檔案(備份文件),也可以在檔案中改變文件,或者向檔案中加

    入新的文件。 tar最初被用來在磁帶上創建檔案,現在,用戶可以在任何設備上創建檔案,如軟盤。利用tar命令,可以把一大堆的文件和目

    錄全部打包成一個文件,這對於備份文件或將幾個文件組合成為一個文件以便於網絡傳輸是非常有用的。 Linux上的tar是GNU版本的。

    語法:tar [主選項+輔選項]文件或者目錄

    使用該命令時,主選項是必須要有的,它告訴tar要做什麼事情,輔選項是輔助使用的,可以選用。

    主選項:

    c創建新的檔案文件。如果用戶想備份一個目錄或是一些文件,就要選擇這個選項。

    r把要存檔的文件追加到檔案文件的未尾。例如用戶已經作好備份文件,又發現還有一個目錄或是一些文件忘記備份了,這時可以使用

    該選項,將忘記的目錄或文件追加到備份文件中。

    t列出檔案文件的內容,查看已經備份了哪些文件。

    u更新文件。就是說,用新增的文件取代原備份文件,如果在備份文件中找不到要更新的文件,則把它追加到備份文件的最後。

    x從檔案文件中釋放文件。

    輔助選項:

    b該選項是為磁帶機設定的。其後跟一數字,用來說明區塊的大小,系統預設值為20(20*512 bytes)。

    f使用檔案文件或設備,這個選項通常是必選的。

    k保存已經存在的文件。例如我們把某個文件還原,在還原的過程中,遇到相同的文件,不會進行覆蓋。

    m在還原文件時,把所有文件的修改時間設定為現在。

    M創建多卷的檔案文件,以便在幾個磁盤中存放。

    v詳細報告tar處理的文件信息。如無此選項,tar不報告文件信息。

    w每一步都要求確認。

    z用gzip來壓縮/解壓縮文件,加上該選項後可以將檔案文件進行壓縮,但還原時也一定要使用該選項進行解壓縮。

    例1:把/home目錄下包括它的子目錄全部做備份文件,備份文件名為usr.tar。

    $ tar cvf usr.tar /home

    例2:把/home目錄下包括它的子目錄全部做備份文件,並進行壓縮,備份文件名為usr.tar.gz 。

    $ tar czvf usr.tar.gz /home

    例3:把usr.tar.gz這個備份文件還原並解壓縮。

    $ tar xzvf usr.tar.gz

    例4:查看usr.tar備份文件的內容,並以分屏方式顯示在顯示器上。

    $ tar tvf usr.tar | more

    要將文件備份到一個特定的設備,只需把設備名作為備份文件名。

    例5:用戶在/dev/fd0設備的軟盤中創建一個備份文件,並將/home目錄中所有的文件都拷貝到備份文件中。

  • IBM專業技術認證計劃

    在當前企業競爭日趨激烈、信息技術日異更新的形勢下,企業經理們已經意識到了新技術的採用、員工的培訓以及人才的保留是企業得以長

    久發展和成功的關鍵。然而,如何評價員工是否掌握和吸收了正確而有效的知識,這也許是企業經理們面臨的另一種挑戰。教育培訓畢竟只

    是一種過程,只有確保員工掌握應有的技能,才能將此技能轉化成有價的產品!

        針對這一企業競爭形勢的新要求,IBM公司專業認證測試中心根據IBM公司的產品分類設計了各種相關的專業認證考試科目,其中包括

    AIX、AS/400、OS/2、DB2、Client/Server、VisualAge Application Development和Lotus等。在國際上,許多企業已從1995年起安排員工

    參加了各專業的認證考試。他們的實踐證明,專業認證不僅提高了員工的技術水平,增強了企業的市場競爭能力,而且更重要的是,這些企

    業由於在更新員工技能方面所付出的努力以及所表現出的遠見卓識,已贏得了企業內外的廣泛尊重。

         IBM中國培訓專業服務部將於1999年繼續全面推行IBM公司專業認證測試中心提供的AIX、AS/400、OS/2、DB2、Client/Server、

    VisualAge Application Development和Lotus等相關的專業技術認證考試。

    通過IBM專業認證的好處:
    →獲得認可的專家證書和贈品。

         →有權將付有您認證證書用於廣告和商務宣傳。

        國際人才

         →增強您的職業潛能,幫助您不斷提高技術支持水平。

         →成為全球公認的高級技術人才。

         →在適當的情況下,IBM會在全球範圍內宣傳您的專長,您的名字將被登記在全球專業認證名錄中。

        技術領先

         →不定期獲得最近計算機產品資料和技術信息。這些資料將以期刊、技術文件或CD-ROM方式寄送給您

         →被IBM邀請參加技術研討會以及展覽會。

         →從IBM提供的技術支持中得到優惠。