掌握SQL四條最基本的數據操作語句:Insert,Select,Update和Delete。 練掌握SQL是數據庫用戶的寶貴财 富。在本文中(zhōng),我(wǒ)(wǒ)們将引導你掌握四條最基本的數據操作語句—SQL的核心功能—來依次介紹比較操作符、選擇斷言以及三值邏輯。當你完成這些學習後,顯然你已經開(kāi)始算是精通SQL了。 在我(wǒ)(wǒ)們開(kāi)始之前,先使用CREATE TABLE語句來創建一(yī)個表(如圖1所示)。DDL語句對數據庫對象如表、列和視進行定義。它們并不對表中(zhōng)的行進行處理,這是因爲DDL語句并不處理數據庫中(zhōng)實際的數據。這些工(gōng)作由另一(yī)類SQL語句—數據操作語言(DML)語句進行處理。 SQL中(zhōng)有四種基本的DML操作:INSERT,SELECT,UPDATE和DELETE。由于這是大(dà)多數SQL用戶經常用到的,我(wǒ)(wǒ)們有必要在此對它們進行一(yī)一(yī)說明。在圖1中(zhōng)我(wǒ)(wǒ)們給出了一(yī)個名爲EMPLOYEES的表。其中(zhōng)的每一(yī)行對應一(yī)個特定的雇員(yuán)記錄。請熟悉這張表,我(wǒ)(wǒ)們在後面的例子中(zhōng)将要用到它。 INSERT語句 用戶可以用INSERT語句将一(yī)行記錄插入到指定的一(yī)個表中(zhōng)。例如,要将雇員(yuán)John Smith的記錄插入到本例的表中(zhōng),可以使用如下(xià)語句: INSERT INTO EMPLOYEES VALUES ('Smith','John','1980-06-10','Los Angles',16,45000); 通過這樣的INSERT語句,系統将試着将這些值填入到相應的列中(zhōng)。這些列按照我(wǒ)(wǒ)們創建表時定義的順序排列。在本例中(zhōng),第一(yī)個值“Smith”将填到第一(yī)個列LAST_NAME中(zhōng);第二個值“John”将填到第二列FIRST_NAME中(zhōng)……以此類推。 我(wǒ)(wǒ)們說過系統會“試着”将值填入,除了執行規則之外(wài)它還要進行類型檢查。如果類型不符(如将一(yī)個字符串填入到類型爲數字的列中(zhōng)),系統将拒絕這一(yī)次操作并返回一(yī)個錯誤信息。 如果SQL拒絕了你所填入的一(yī)列值,語句中(zhōng)其他各列的值也不會填入。這是因爲SQL提供對事務的支持。一(yī)次事務将數據庫從一(yī)種一(yī)緻性轉移到另一(yī)種一(yī)緻性。如果事務的某一(yī)部分(fēn)失敗,則整個事務都會失敗,系統将會被恢複(或稱之爲回退)到此事務之前的狀态。 回到原來的INSERT的例子,請注意所有的整形十進制數都不需要用單引号引起來,而字符串和日期類型的值都要用單引号來區别。爲了增加可讀性而在數字間插入逗号将會引起錯誤。記住,在SQL中(zhōng)逗号是元素的分(fēn)隔符。 同樣要注意輸入文字值時要使用單引号。雙引号用來封裝限界标識符。 對于日期類型,我(wǒ)(wǒ)們必須使用SQL标準日期格式(yyyy-mm-dd),但是在系統中(zhōng)可以進行定義,以接受其他的格式。當然,2000年臨近,請你最好還是使用四位來表示年份。 既然你已經理解了INSERT語句是怎樣工(gōng)作的了,讓我(wǒ)(wǒ)們轉到EMPLOYEES表中(zhōng)的其他部分(fēn): INSERT INTO EMPLOYEES VALUES ('Bunyan','Paul','1970-07-04','Boston',12,70000); INSERT INTO EMPLOYEES VALUES ('John','Adams','1992-01-21','Boston',20,100000); INSERT INTO EMPLOYEES VALUES ('Smith','Pocahontas','1976-04-06','Los Angles',12,100000); INSERT INTO EMPLOYEES VALUES ('Smith','Bessie','1940-05-02','Boston',5,200000); INSERT INTO EMPLOYEES VALUES ('Jones','Davy','1970-10-10','Boston',8,45000); INSERT INTO EMPLOYEES VALUES ('Jones','Indiana','1992-02-01','Chicago',NULL,NULL); 在最後一(yī)項中(zhōng),我(wǒ)(wǒ)們不知(zhī)道Jones先生(shēng)的工(gōng)薪級别和年薪,所以我(wǒ)(wǒ)們輸入NULL(不要引号)。NULL是SQL中(zhōng)的一(yī)種特殊情況,我(wǒ)(wǒ)們以後将進行詳細的讨論。現在我(wǒ)(wǒ)們隻需認爲NULL表示一(yī)種未知(zhī)的值。 有時,像我(wǒ)(wǒ)們剛才所讨論的情況,我(wǒ)(wǒ)們可能希望對某一(yī)些而不是全部的列進行賦值。除了對要省略的列輸入NULL外(wài),還可以采用另外(wài)一(yī)種INSERT語句,如下(xià): INSERT INTO EMPLOYEES(FIRST_NAME, LAST_NAME,HIRE_DATE, BRANCH_OFFICE) VALUE( 'Indiana','Jones','1992-02-01','Indianapolis'); 這樣,我(wǒ)(wǒ)們先在表名之後列出一(yī)系列列名。未列出的列中(zhōng)将自動填入缺省值,如果沒有設置缺省值則填入NULL。請注意我(wǒ)(wǒ)們改變了列的順序,而值的順序要對應新的列的順序。如果該語句中(zhōng)省略了FIRST_NAME和LAST_NAME項(這兩項規定不能爲空),SQL操作将失敗。 讓我(wǒ)(wǒ)們來看一(yī)看上述INSERT語句的語法圖: INSERT INTO table [(column { ,column})] VALUES (columnvalue [{,columnvalue}]); 和前一(yī)篇文章中(zhōng)一(yī)樣,我(wǒ)(wǒ)們用方括号來表示可選項,大(dà)括号表示可以重複任意次數的項(不能在實際的SQL語句中(zhōng)使用這些特殊字符)。VALUE子句和可選的列名列表中(zhōng)必須使用圓括号。 SELECT語句 SELECT語句可以從一(yī)個或多個表中(zhōng)選取特定的行和列。因爲查詢和檢索數據是數據庫管理中(zhōng)最重要的功能,所以SELECT語句在SQL中(zhōng)是工(gōng)作量最大(dà)的部分(fēn)。實際上,僅僅是訪問數據庫來分(fēn)析數據并生(shēng)成報表的人可以對其他SQL語句一(yī)竅不通。 SELECT語句的結果通常是生(shēng)成另外(wài)一(yī)個表。在執行過程中(zhōng)系統根據用戶的标準從數據庫中(zhōng)選出匹配的行和列,并将結果放(fàng)到臨時的表中(zhōng)。在直接SQL(direct SQL)中(zhōng),它将結果顯示在終端的顯示屏上,或者将結果送到打印機或文件中(zhōng)。也可以結合其他SQL語句來将結果放(fàng)到一(yī)個已知(zhī)名稱的表中(zhōng)。 SELECT語句功能強大(dà)。雖然表面上看來它隻用來完成本文第一(yī)部分(fēn)中(zhōng)提到的關系代數運算“選擇”(或稱“限制”),但實際上它也可以完成其他兩種關系運算—“投影”和“連接”,SELECT語句還可以完成聚合計算并對數據進行排序。 SELECT語句最簡單的語法如下(xià): SELECT columns FROM tables; 當我(wǒ)(wǒ)們以這種形式執行一(yī)條SELECT語句時,系統返回由所選擇的列以及用戶選擇的表中(zhōng)所有指定的行組成的一(yī)個結果表。這就是實現關系投影運算的一(yī)個形式。 讓我(wǒ)(wǒ)們看一(yī)下(xià)使用圖1中(zhōng)EMPLOYEES表的一(yī)些例子(這個表是我(wǒ)(wǒ)們以後所有SELECT語句實例都要使用的。而我(wǒ)(wǒ)們在圖2和圖3中(zhōng)給出了查詢的實際結果。我(wǒ)(wǒ)們将在其他的例子中(zhōng)使用這些結果)。 假設你想查看雇員(yuán)工(gōng)作部門的列表。那下(xià)面就是你所需要編寫的SQL查詢: SELECT BRANCH_OFFICE FROM EMPLOYEES; 以上SELECT語句的執行将産生(shēng)如圖2中(zhōng)表2所示的結果。 由于我(wǒ)(wǒ)們在SELECT語句中(zhōng)隻指定了一(yī)個列,所以我(wǒ)(wǒ)們的結果表中(zhōng)也隻有一(yī)個列。注意結果表中(zhōng)具有重複的行,這是因爲有多個雇員(yuán)在同一(yī)部門工(gōng)作(記住SQL從所選的所有行中(zhōng)将值返回)。要消除結果中(zhōng)的重複行,隻要在SELECT語句中(zhōng)加上DISTINCT子句: SELECT DISTINCT BRANCH_OFFICE FROM EMPLOYEES; 這次查詢的結果如表3所示。 現在已經消除了重複的行,但結果并不是按照順序排列的。如果你希望以字母表順序将結果列出又(yòu)該怎麽做呢?隻要使用ORDER BY子句就可以按照升序或降序來排列結果: SELECT DISTINCT BRANCH_OFFICE FROM EMPLOYEES ORDER BY BRANCH_OFFICE ASC; 這一(yī)查詢的結果如表4所示。請注意在ORDER BY之後是如何放(fàng)置列名BRANCH _OFFICE的,這就是我(wǒ)(wǒ)們想要對其進行排序的列。爲什麽即使是結果表中(zhōng)隻有一(yī)個列時我(wǒ)(wǒ)們也必須指出列名呢?這是因爲我(wǒ)(wǒ)們還能夠按照表中(zhōng)其他列進行排序,即使它們并不顯示出來。列名BRANCH_ OFFICE之後的關鍵字ASC表示按照升序排列。如果你希望以降序排列,那麽可以用關鍵字DESC。 同樣我(wǒ)(wǒ)們應該指出ORDER BY子句隻将臨時表中(zhōng)的結果進行排序;并不影響原來的表。 假設我(wǒ)(wǒ)們希望得到按部門排序并從工(gōng)資(zī)最高的雇員(yuán)到工(gōng)資(zī)最低的雇員(yuán)排列的列表。除了工(gōng)資(zī)括号中(zhōng)的内容,我(wǒ)(wǒ)們還希望看到按照聘用時間從最近聘用的雇員(yuán)開(kāi)始列出的列表。以下(xià)是你将要用到的語句: SELECT BRANCH_OFFICE,FIRST_NAME,LAST_NAME,SALARY,HIRE_DATE FROM EMPLOYEES ORDER BY SALARY DESC,HIRE_DATE DESC; 這裏我(wǒ)(wǒ)們進行了多列的選擇和排序。排序的優先級由語句中(zhōng)的列名順序所決定。SQL将先對列出的第一(yī)個列進行排序。如果在第一(yī)個列中(zhōng)出現了重複的行時,這些行将被按照第二列進行排序,如果在第二列中(zhōng)又(yòu)出現了重複的行時,這些行又(yòu)将被按照第三列進行排序……如此類推。這次查詢的結果如表5所示。 将一(yī)個很長的表中(zhōng)的所有列名寫出來是一(yī)件相當麻煩的事,所以SQL允許在選擇表中(zhōng)所有的列時使用*号: SELECT * FROM EMPLOYEES; 這次查詢返回整個EMPLOYEES表,如表1所示。 下(xià)面我(wǒ)(wǒ)們對開(kāi)始時給出的SELECT語句的語法進行一(yī)下(xià)更新(豎直線表示一(yī)個可選項,允許在其中(zhōng)選擇一(yī)項。): SELECT [DISTINCT] (column [{, columns}])| * FROM table [ {, table}] [ORDER BY column [ASC] | DESC [ {, column [ASC] | DESC }]]; 定義選擇标準 在我(wǒ)(wǒ)們目前所介紹的SELECT語句中(zhōng),我(wǒ)(wǒ)們對結果表中(zhōng)的列作出了選擇但返回的是表中(zhōng)所有的行。讓我(wǒ)(wǒ)們看一(yī)下(xià)如何對SELECT語句進行限制使得它隻返回希望得到的行: SELECT columns FROM tables [WHERE predicates]; WHERE子句對條件進行了設置,隻有滿足條件的行才被包括到結果表中(zhōng)。這些條件由斷言(predicate)進行指定(斷言指出了關于某件事情的一(yī)種可能的事實)。如果該斷言對于某個給定的行成立,該行将被包括到結果表中(zhōng),否則該行被忽略。在SQL語句中(zhōng)斷言通常通過比較來表示。例如,假如你需要查詢所有姓爲Jones的職員(yuán),則可以使用以下(xià)SELECT語句: SELECT * FROM EMPLOYEES WHERE LAST_NAME = 'Jones'; LAST_NAME = 'Jones'部分(fēn)就是斷言。在執行該語句時,SQL将每一(yī)行的LAST_NAME列與“Jones”進行比較。如果某一(yī)職員(yuán)的姓爲“Jones”,即斷言成立,該職員(yuán)的信息将被包括到結果表中(zhōng)(見表6)。 使用最多的六種比較 我(wǒ)(wǒ)們上例中(zhōng)的斷言包括一(yī)種基于“等值”的比較(LAST_NAME = 'Jones'),但是SQL斷言還可以包含其他幾種類型的比較。其中(zhōng)最常用的爲: 等于 = 不等于 <> 小(xiǎo)于 < 大(dà)于 > 小(xiǎo)于或等于 <= 大(dà)于或等于 >= 下(xià)面給出了不是基于等值比較的一(yī)個例子: SELECT * FROM EMPLOYEES WHERE SALARY > 50000; 這一(yī)查詢将返回年薪高于$50,000.00的職員(yuán)(參見表7)。 邏輯連接符 有時我(wǒ)(wǒ)們需要定義一(yī)條不止一(yī)種斷言的SELECT語句。舉例來說,如果你僅僅想查看Davy Jones的信息的話(huà),表6中(zhōng)的結果将是不正确的。爲了進一(yī)步定義一(yī)個WHERE子句,用戶可以使用邏輯連接符AND,OR和NOT。爲了隻得到職員(yuán)Davy Jones的記錄,用戶可以輸入如下(xià)語句: SELECT * FROM EMPLOYEES WHERE LAST_NAME = 'Jones' AND FIRST_NAME = 'Davy'; 在本例中(zhōng),我(wǒ)(wǒ)們通過邏輯連接符AND将兩個斷言連接起來。隻有兩個斷言都滿足時整個表達式才會滿足。如果用戶需要定義一(yī)個SELECT語句來使得當其中(zhōng)任何一(yī)項成立就滿足條件時,可以使用OR連接符: SELECT * FROM EMPLOYEES WHERE LAST_NAME = 'Jones' OR LAST_NAME = 'Smith'; 有時定義一(yī)個斷言的最好方法是通過相反的描述來說明。如果你想要查看除了Boston辦事處的職員(yuán)以外(wài)的其他所有職員(yuán)的信息時,你可以進行如下(xià)的查詢: SELECT * FROM EMPLOYEES WHERE NOT(BRANCH_OFFICE = 'Boston'); 關鍵字NOT後面跟着用圓括号括起來的比較表達式。其結果是對結果取否定。如果某一(yī)職員(yuán)所在部門的辦事處在Boston,括号内的表達式返回true,但是NOT操作符将該值取反,所以該行将不被選中(zhōng)。 斷言可以與其他的斷言嵌套使用。爲了保證它們以正确的順序進行求值,可以用括号将它們括起來: SELECT * FROM EMPLOYEES WHERE (LAST_NAME = 'Jones' AND FIRST_NAME = 'Indiana') OR (LAST_NAME = 'Smith' AND FIRST_NAME = 'Bessie'); SQL沿用數學上标準的表達式求值的約定—圓括号内的表達式将最先進行求值,其他表達式将從左到右進行求值。 以上對邏輯連接符進行了說明,在對下(xià)面的内容進行說明之前,我(wǒ)(wǒ)們再一(yī)次對SELECT語句的語法進行更新: SELECT [DISTINCT] (column [{, column } ] )| * FROM table [ { , table} ] [ORDER BY column [ASC] | [DESC [{ , column [ASC] | [DESC } ] ] WHERE predicate [ { logical-connector predicate } ]; NULL和三值邏輯 在SQL中(zhōng)NULL是一(yī)個複雜(zá)的話(huà)題,關于NULL的詳細描述更适合于在SQL的高級教程而不是現在的入門教程中(zhōng)進行介紹。但由于NULL需要進行特殊處理,并且你也很可能會遇到它,所以我(wǒ)(wǒ)們還是簡略地進行一(yī)下(xià)說明。 首先,在斷言中(zhōng)進行NULL判斷時需要特殊的語法。例如,如果用戶需要顯示所有年薪未知(zhī)的職員(yuán)的全部信息,用戶可以使用如下(xià)SELECT語句: SELECT * FROM EMPLOYEES WHERE SALARY IS NULL; 相反,如果用戶需要所有已知(zhī)年薪數據的職員(yuán)的信息,你可以使用以下(xià)語句: SELECT * FROM EMPLOYEES WHERE SALARY IS NOT NULL; 請注意我(wǒ)(wǒ)們在列名之後使用了關鍵字IS NULL或IS NOT NULL,而不是标準的比較形式:COLUMN = NULL、COLUMN <> NULL或是邏輯操作符NOT(NULL)。 這種形式相當簡單。但當你不明确地測試NULL(而它們确實存在)時,事情會變得很混亂。 例如,回過頭來看我(wǒ)(wǒ)們圖1中(zhōng)的EM-PLOYEES表,可以看到Indiana Jones的工(gōng)薪等級或年薪值都是未知(zhī)的。這兩個列都包含NULL。可以想象運行如下(xià)的查詢: SELECT * FROM EMPLOYEES WHERE GRADE <= SALARY; 此時,Indiana Jones應該出現在結果表中(zhōng)。因爲NULL都是相等的,所以可以想象它們是能夠通過GRADE小(xiǎo)于等于SALARY的檢查的。這其實是一(yī)個毫無疑義的查詢,但是并沒有關系。SQL允許進行這樣的比較,隻要兩個列都是數字類型的。然而,Indiana Jones并沒有出現在查詢的結果中(zhōng),爲什麽? 正如我(wǒ)(wǒ)們早先提到過的,NULL表示未知(zhī)的值(而不是象某些人所想象的那樣表示一(yī)個爲NULL的值)。對于SQL來說意味着這個值是未知(zhī)的,而隻要這個值爲未知(zhī),就不能将其與其他值比較(即使其他值也是NULL)。所以SQL允許除了在true 和false之外(wài)還有第三種類型的真值,稱之爲“非确定”(unknown)值。 如果比較的兩邊都是NULL,整個斷言就被認爲是非确定的。将一(yī)個非确定斷言取反或使用AND或OR與其他斷言進行合并之後,其結果仍是非确定的。由于結果表中(zhōng)隻包括斷言值爲“真”的行,所以NULL不可能滿足該檢查。從而需要使用特殊的操作符IS NULL和IS NOT NULL。 UPDATE語句 UPDATE語句允許用戶在已知(zhī)的表中(zhōng)對現有的行進行修改。 例如,我(wǒ)(wǒ)們剛剛發現Indiana Jones的等級爲16,工(gōng)資(zī)爲$40,000.00,我(wǒ)(wǒ)們可以通過下(xià)面的SQL語句對數據庫進行更新(并清除那些煩人的NULL)。 UPDATE EMPLOYEES SET GRADE = 16, SALARY = 40000 WHERE FIRST_NAME = 'Indiana' AND LAST_NAME = 'Jones'; 上面的例子說明了一(yī)個單行更新,但是UPDATE語句可以對多行進行操作。滿足WHERE條件的所有行都将被更新。如果,你想讓Boston辦事處中(zhōng)的所有職員(yuán)搬到New York,你可以使用如下(xià)語句: UPDATE EMPLOYEES SET BRANCH_OFFICE = 'New York' WHERE BRANCH_OFFICE = 'Boston'; 如果忽略WHERE子句,表中(zhōng)所有行中(zhōng)的部門值都将被更新爲'New York'。 UPDATE語句的語法流圖如下(xià)面所示: UPDATE table SET column = value [{, column = value}] [ WHERE predicate [ { logical-connector predicate}]]; DELETE語句 DELETE語句用來删除已知(zhī)表中(zhōng)的行。如同UPDATE語句中(zhōng)一(yī)樣,所有滿足WHERE子句中(zhōng)條件的行都将被删除。由于SQL中(zhōng)沒有UNDO語句或是“你确認删除嗎(ma)?”之類的警告,在執行這條語句時千萬要小(xiǎo)心。如果決定取消Los Angeles辦事處并解雇辦事處的所有職員(yuán),這一(yī)卑鄙的工(gōng)作可以由以下(xià)這條語句來實現: DELETE FROM EMPLOYEES WHERE BRANCH_OFFICE = 'Los Angeles'; 如同UPDATE語句中(zhōng)一(yī)樣,省略WHERE子句将使得操作施加到表中(zhōng)所有的行。 DELETE語句的語法流圖如下(xià)面所示: DELETE FROM table [WHERE predicate [ { logical-connector predicate} ] ]; 現在我(wǒ)(wǒ)們完成了數據操作語言(DML)的主要語句的介紹。我(wǒ)(wǒ)們并沒有對SQL能完成的所有功能進行說明。SQL還提供了許多的功能,如求平均值、求和以及其他對表中(zhōng)數據的計算,此外(wài)SQL還能完成從多個表中(zhōng)進行查詢(多表查詢,或稱之爲連接)的工(gōng)作。這種語言還允許你使用GRANT和REVOKE命令控制使用者的數據訪問權限。 |