掌握sql四條最基本的數(shù)據(jù)操作語句:insert,select,update和delete。

   練掌握sql是數(shù)據(jù)庫用戶的寶貴財(cái) 富。在本文中,我們將引導(dǎo)你掌握四條最基本的數(shù)據(jù)操作語句—sql的核心功能—來依次介紹比較操作符、選擇斷言以及三值邏輯。當(dāng)你完成這些學(xué)習(xí)后,顯然你已經(jīng)開始算是精通sql了。

  在我們開始之前,先使用create table語句來創(chuàng)建一個(gè)表(如圖1所示)。ddl語句對數(shù)據(jù)庫對象如表、列和視進(jìn)行定義。它們并不對表中的行進(jìn)行處理,這是因?yàn)閐dl語句并不處理數(shù)據(jù)庫中實(shí)際的數(shù)據(jù)。這些工作由另一類sql語句—數(shù)據(jù)操作語言(dml)語句進(jìn)行處理。

  sql中有四種基本的dml操作:insert,select,update和delete。由于這是大多數(shù)sql用戶經(jīng)常用到的,我們有必要在此對它們進(jìn)行一一說明。在圖1中我們給出了一個(gè)名為employees的表。其中的每一行對應(yīng)一個(gè)特定的雇員記錄。請熟悉這張表,我們在后面的例子中將要用到它。

連接查詢

通過連接運(yùn)算符可以實(shí)現(xiàn)多個(gè)表查詢。連接是關(guān)系數(shù)據(jù)庫模型的主要特點(diǎn),也是它區(qū)別于其它類型

數(shù)據(jù)庫管理系統(tǒng)的一個(gè)標(biāo)志。

在關(guān)系數(shù)據(jù)庫管理系統(tǒng)中,表建立時(shí)各數(shù)據(jù)之間的關(guān)系不必確定,常把一個(gè)實(shí)體的所有信息存放在

一個(gè)表中。當(dāng)檢索數(shù)據(jù)時(shí),通過連接操作查詢出存放在多個(gè)表中的不同實(shí)體的信息。連接操作給用戶帶

來很大的靈活性,他們可以在任何時(shí)候增加新的數(shù)據(jù)類型。為不同實(shí)體創(chuàng)建新的表,爾后通過連接進(jìn)行

查詢。

連接可以在select 語句的from子句或where子句中建立,似是而非在from子句中指出連接時(shí)有助于

將連接操作與where子句中的搜索條件區(qū)分開來。所以,在transact-sql中推薦使用這種方法。

sql-92標(biāo)準(zhǔn)所定義的from子句的連接語法格式為:

from join_table join_type join_table

[on (join_condition)]

其中join_table指出參與連接操作的表名,連接可以對同一個(gè)表操作,也可以對多表操作,對同一

個(gè)表操作的連接又稱做自連接。

join_type 指出連接類型,可分為三種:內(nèi)連接、外連接和交叉連接。內(nèi)連接(inner join)使用比

較運(yùn)算符進(jìn)行表間某(些)列數(shù)據(jù)的比較操作,并列出這些表中與連接條件相匹配的數(shù)據(jù)行。根據(jù)所使用

的比較方式不同,內(nèi)連接又分為等值連接、自然連接和不等連接三種。

外連接分為左外連接(left outer join或left join)、右外連接(right outer join或right join)

和全外連接(full outer join或full join)三種。與內(nèi)連接不同的是,外連接不只列出與連接條件相匹

配的行,而是列出左表(左外連接時(shí))、右表(右外連接時(shí))或兩個(gè)表(全外連接時(shí))中所有符合搜索條件的

數(shù)據(jù)行。

交叉連接(cross join)沒有where 子句,它返回連接表中所有數(shù)據(jù)行的笛卡爾積,其結(jié)果集合中的

數(shù)據(jù)行數(shù)等于第一個(gè)表中符合查詢條件的數(shù)據(jù)行數(shù)乘以第二個(gè)表中符合查詢條件的數(shù)據(jù)行數(shù)。

連接操作中的on (join_condition) 子句指出連接條件,它由被連接表中的列和比較運(yùn)算符、邏輯

運(yùn)算符等構(gòu)成。

無論哪種連接都不能對text、ntext和image數(shù)據(jù)類型列進(jìn)行直接連接,但可以對這三種列進(jìn)行間接

連接。例如:

select p1.pub_id,p2.pub_id,p1.pr_info

from pub_info as p1 inner join pub_info as p2

on datalength(p1.pr_info)=datalength(p2.pr_info)

 

(一)內(nèi)連接

內(nèi)連接查詢操作列出與連接條件匹配的數(shù)據(jù)行,它使用比較運(yùn)算符比較被連接列的列值。內(nèi)連接分

三種:

1、等值連接:在連接條件中使用等于號(=)運(yùn)算符比較被連接列的列值,其查詢結(jié)果中列出被連接

表中的所有列,包括其中的重復(fù)列。

2、不等連接: 在連接條件使用除等于運(yùn)算符以外的其它比較運(yùn)算符比較被連接的列的列值。這些

運(yùn)算符包括>、>=、<=、<、!>、!<和<>。

3、自然連接:在連接條件中使用等于(=)運(yùn)算符比較被連接列的列值,但它使用選擇列表指出查詢

結(jié)果集合中所包括的列,并刪除連接表中的重復(fù)列。

例,下面使用等值連接列出authors和publishers表中位于同一城市的作者和出版社:

select *

from authors as a inner join publishers as p

on a.city=p.city

 

又如使用自然連接,在選擇列表中刪除authors 和publishers 表中重復(fù)列(city和state):

select a.*,p.pub_id,p.pub_name,p.country

from authors as a inner join publishers as p

on a.city=p.city

 

(二)外連接

內(nèi)連接時(shí),返回查詢結(jié)果集合中的僅是符合查詢條件( where 搜索條件或 having 條件)和連接條件

的行。而采用外連接時(shí),它返回到查詢結(jié)果集合中的不僅包含符合連接條件的行,而且還包括左表(左外

連接時(shí))、右表(右外連接時(shí))或兩個(gè)邊接表(全外連接)中的所有數(shù)據(jù)行。

如下面使用左外連接將論壇內(nèi)容和作者信息連接起來:

select a.*,b.* from luntan left join usertable as b

on a.username=b.username

 

下面使用全外連接將city表中的所有作者以及user表中的所有作者,以及他們所在的城市:

select a.*,b.*

from city as a full outer join user as b

on a.username=b.username

 

(三)交叉連接

交叉連接不帶where 子句,它返回被連接的兩個(gè)表所有數(shù)據(jù)行的笛卡爾積,返回到結(jié)果集合中的數(shù)

據(jù)行數(shù)等于第一個(gè)表中符合查詢條件的數(shù)據(jù)行數(shù)乘以第二個(gè)表中符合查詢條件的數(shù)據(jù)行數(shù)。

例,titles表中有6類圖書,而publishers表中有8家出版社,則下列交叉連接檢索到的記錄數(shù)將等

于6*8=48行。

select type,pub_name

from titles cross join publishers

order by type

union運(yùn)算符可以將兩個(gè)或兩個(gè)以上上select語句的查詢結(jié)果集合合并成一個(gè)結(jié)果集合顯示,即執(zhí)行聯(lián)

合查詢。union的語法格式為:

select_statement

union [all] selectstatement

[union [all] selectstatement][…n]

其中selectstatement為待聯(lián)合的select查詢語句。

all選項(xiàng)表示將所有行合并到結(jié)果集合中。不指定該項(xiàng)時(shí),被聯(lián)合查詢結(jié)果集合中的重復(fù)行將只保留一

行。

聯(lián)合查詢時(shí),查詢結(jié)果的列標(biāo)題為第一個(gè)查詢語句的列標(biāo)題。因此,要定義列標(biāo)題必須在第一個(gè)查詢語

句中定義。要對聯(lián)合查詢結(jié)果排序時(shí),也必須使用第一查詢語句中的列名、列標(biāo)題或者列序號。

在使用union 運(yùn)算符時(shí),應(yīng)保證每個(gè)聯(lián)合查詢語句的選擇列表中有相同數(shù)量的表達(dá)式,并且每個(gè)查詢選

擇表達(dá)式應(yīng)具有相同的數(shù)據(jù)類型,或是可以自動(dòng)將它們轉(zhuǎn)換為相同的數(shù)據(jù)類型。在自動(dòng)轉(zhuǎn)換時(shí),對于數(shù)值類

型,系統(tǒng)將低精度的數(shù)據(jù)類型轉(zhuǎn)換為高精度的數(shù)據(jù)類型。

在包括多個(gè)查詢的union語句中,其執(zhí)行順序是自左至右,使用括號可以改變這一執(zhí)行順序。例如:

查詢1 union (查詢2 union 查詢3)

  insert語句

  用戶可以用insert語句將一行記錄插入到指定的一個(gè)表中。例如,要將雇員john smith的記錄插入到本例的表中,可以使用如下語句:

  insert into employees values

   (''smith'',''john'',''1980-06-10'',

   ''los angles'',16,45000);

  通過這樣的insert語句,系統(tǒng)將試著將這些值填入到相應(yīng)的列中。這些列按照我們創(chuàng)建表時(shí)定義的順序排列。在本例中,第一個(gè)值“smith”將填到第一個(gè)列l(wèi)ast_name中;第二個(gè)值“john”將填到第二列first_name中……以此類推。

  我們說過系統(tǒng)會(huì)“試著”將值填入,除了執(zhí)行規(guī)則之外它還要進(jìn)行類型檢查。如果類型不符(如將一個(gè)字符串填入到類型為數(shù)字的列中),系統(tǒng)將拒絕這一次操作并返回一個(gè)錯(cuò)誤信息。

  如果sql拒絕了你所填入的一列值,語句中其他各列的值也不會(huì)填入。這是因?yàn)閟ql提供對事務(wù)的支持。一次事務(wù)將數(shù)據(jù)庫從一種一致性轉(zhuǎn)移到另一種一致性。如果事務(wù)的某一部分失敗,則整個(gè)事務(wù)都會(huì)失敗,系統(tǒng)將會(huì)被恢復(fù)(或稱之為回退)到此事務(wù)之前的狀態(tài)。

   回到原來的insert的例子,請注意所有的整形十進(jìn)制數(shù)都不需要用單引號引起來,而字符串和日期類型的值都要用單引號來區(qū)別。為了增加可讀性而在數(shù)字間插入逗號將會(huì)引起錯(cuò)誤。記住,在sql中逗號是元素的分隔符。

  同樣要注意輸入文字值時(shí)要使用單引號。雙引號用來封裝限界標(biāo)識(shí)符。

  對于日期類型,我們必須使用sql標(biāo)準(zhǔn)日期格式(yyyy-mm-dd),但是在系統(tǒng)中可以進(jìn)行定義,以接受其他的格式。當(dāng)然,2000年臨近,請你最好還是使用四位來表示年份。

  既然你已經(jīng)理解了insert語句是怎樣工作的了,讓我們轉(zhuǎn)到employees表中的其他部分:

  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);

  在最后一項(xiàng)中,我們不知道jones先生的工薪級別和年薪,所以我們輸入null(不要引號)。null是sql中的一種特殊情況,我們以后將進(jìn)行詳細(xì)的討論。現(xiàn)在我們只需認(rèn)為null表示一種未知的值。

  有時(shí),像我們剛才所討論的情況,我們可能希望對某一些而不是全部的列進(jìn)行賦值。除了對要省略的列輸入null外,還可以采用另外一種insert語句,如下:

  insert into employees(

   first_name, last_name,

   hire_date, branch_office)

  value(

   ''indiana'',''jones'',

   ''1992-02-01'',''indianapolis'');

  這樣,我們先在表名之后列出一系列列名。未列出的列中將自動(dòng)填入缺省值,如果沒有設(shè)置缺省值則填入null。請注意我們改變了列的順序,而值的順序要對應(yīng)新的列的順序。如果該語句中省略了first_name和last_name項(xiàng)(這兩項(xiàng)規(guī)定不能為空),sql操作將失敗。

  讓我們來看一看上述insert語句的語法圖:

  insert into table

   [(column { ,column})]

  values

   (columnvalue [{,columnvalue}]);

  和前一篇文章中一樣,我們用方括號來表示可選項(xiàng),大括號表示可以重復(fù)任意次數(shù)的項(xiàng)(不能在實(shí)際的sql語句中使用這些特殊字符)。value子句和可選的列名列表中必須使用圓括號。

  select語句

  select語句可以從一個(gè)或多個(gè)表中選取特定的行和列。因?yàn)椴樵兒蜋z索數(shù)據(jù)是數(shù)據(jù)庫管理中最重要的功能,所以select語句在sql中是工作量最大的部分。實(shí)際上,僅僅是訪問數(shù)據(jù)庫來分析數(shù)據(jù)并生成報(bào)表的人可以對其他sql語句一竅不通。

  select語句的結(jié)果通常是生成另外一個(gè)表。在執(zhí)行過程中系統(tǒng)根據(jù)用戶的標(biāo)準(zhǔn)從數(shù)據(jù)庫中選出匹配的行和列,并將結(jié)果放到臨時(shí)的表中。在直接sql(direct sql)中,它將結(jié)果顯示在終端的顯示屏上,或者將結(jié)果送到打印機(jī)或文件中。也可以結(jié)合其他sql語句來將結(jié)果放到一個(gè)已知名稱的表中。

  select語句功能強(qiáng)大。雖然表面上看來它只用來完成本文第一部分中提到的關(guān)系代數(shù)運(yùn)算“選擇”(或稱“限制”),但實(shí)際上它也可以完成其他兩種關(guān)系運(yùn)算—“投影”和“連接”,select語句還可以完成聚合計(jì)算并對數(shù)據(jù)進(jìn)行排序。

  select語句最簡單的語法如下:

  select columns from tables;

  當(dāng)我們以這種形式執(zhí)行一條select語句時(shí),系統(tǒng)返回由所選擇的列以及用戶選擇的表中所有指定的行組成的一個(gè)結(jié)果表。這就是實(shí)現(xiàn)關(guān)系投影運(yùn)算的一個(gè)形式。

  讓我們看一下使用圖1中employees表的一些例子(這個(gè)表是我們以后所有select語句實(shí)例都要使用的。而我們在圖2和圖3中給出了查詢的實(shí)際結(jié)果。我們將在其他的例子中使用這些結(jié)果)。

  假設(shè)你想查看雇員工作部門的列表。那下面就是你所需要編寫的sql查詢:

  select branch_office from employees;

  以上select語句的執(zhí)行將產(chǎn)生如圖2中表2所示的結(jié)果。

  由于我們在select語句中只指定了一個(gè)列,所以我們的結(jié)果表中也只有一個(gè)列。注意結(jié)果表中具有重復(fù)的行,這是因?yàn)橛卸鄠€(gè)雇員在同一部門工作(記住sql從所選的所有行中將值返回)。要消除結(jié)果中的重復(fù)行,只要在select語句中加上distinct子句:

  select distinct branch_office

  from employees;

  這次查詢的結(jié)果如表3所示。

  現(xiàn)在已經(jīng)消除了重復(fù)的行,但結(jié)果并不是按照順序排列的。如果你希望以字母表順序?qū)⒔Y(jié)果列出又該怎么做呢?只要使用order by子句就可以按照升序或降序來排列結(jié)果:

  select distinct branch_office

  from employees

  order by branch_office asc;

  這一查詢的結(jié)果如表4所示。請注意在order by之后是如何放置列名branch _office的,這就是我們想要對其進(jìn)行排序的列。為什么即使是結(jié)果表中只有一個(gè)列時(shí)我們也必須指出列名呢?這是因?yàn)槲覀冞€能夠按照表中其他列進(jìn)行排序,即使它們并不顯示出來。列名branch_ office之后的關(guān)鍵字asc表示按照升序排列。如果你希望以降序排列,那么可以用關(guān)鍵字desc。

  同樣我們應(yīng)該指出order by子句只將臨時(shí)表中的結(jié)果進(jìn)行排序;并不影響原來的表。

  假設(shè)我們希望得到按部門排序并從工資最高的雇員到工資最低的雇員排列的列表。除了工資括號中的內(nèi)容,我們還希望看到按照聘用時(shí)間從最近聘用的雇員開始列出的列表。以下是你將要用到的語句:

  select branch_office,first_name,

   last_name,salary,hire_date

  from employees

  order by salary desc,

   hire_date desc;

  這里我們進(jìn)行了多列的選擇和排序。排序的優(yōu)先級由語句中的列名順序所決定。sql將先對列出的第一個(gè)列進(jìn)行排序。如果在第一個(gè)列中出現(xiàn)了重復(fù)的行時(shí),這些行將被按照第二列進(jìn)行排序,如果在第二列中又出現(xiàn)了重復(fù)的行時(shí),這些行又將被按照第三列進(jìn)行排序……如此類推。這次查詢的結(jié)果如表5所示。

  將一個(gè)很長的表中的所有列名寫出來是一件相當(dāng)麻煩的事,所以sql允許在選擇表中所有的列時(shí)使用*號:

  select * from employees;

  這次查詢返回整個(gè)employees表,如表1所示。

   下面我們對開始時(shí)給出的select語句的語法進(jìn)行一下更新(豎直線表示一個(gè)可選項(xiàng),允許在其中選擇一項(xiàng)。):

  select [distinct]

   (column [{, columns}])| *

  from table [ {, table}]

  [order by column [asc] | desc

   [ {, column [asc] | desc }]];

  定義選擇標(biāo)準(zhǔn)

  在我們目前所介紹的select語句中,我們對結(jié)果表中的列作出了選擇但返回的是表中所有的行。讓我們看一下如何對select語句進(jìn)行限制使得它只返回希望得到的行:

  select columns from tables [where predicates];

  where子句對條件進(jìn)行了設(shè)置,只有滿足條件的行才被包括到結(jié)果表中。這些條件由斷言(predicate)進(jìn)行指定(斷言指出了關(guān)于某件事情的一種可能的事實(shí))。如果該斷言對于某個(gè)給定的行成立,該行將被包括到結(jié)果表中,否則該行被忽略。在sql語句中斷言通常通過比較來表示。例如,假如你需要查詢所有姓為jones的職員,則可以使用以下select語句:

  select * from employees

  where last_name = ''jones'';

  last_name = ''jones''部分就是斷言。在執(zhí)行該語句時(shí),sql將每一行的last_name列與“jones”進(jìn)行比較。如果某一職員的姓為“jones”,即斷言成立,該職員的信息將被包括到結(jié)果表中(見表6)。

  使用最多的六種比較

  我們上例中的斷言包括一種基于“等值”的比較(last_name = ''jones''),但是sql斷言還可以包含其他幾種類型的比較。其中最常用的為:

  等于 =

  不等于 <>

  小于 <

  大于 >

  小于或等于 <=

  大于或等于 >=

  下面給出了不是基于等值比較的一個(gè)例子:

  select * from employees

  where salary > 50000;

  這一查詢將返回年薪高于$50,000.00的職員(參見表7)。

  邏輯連接符

  有時(shí)我們需要定義一條不止一種斷言的select語句。舉例來說,如果你僅僅想查看davy jones的信息的話,表6中的結(jié)果將是不正確的。為了進(jìn)一步定義一個(gè)where子句,用戶可以使用邏輯連接符and,or和not。為了只得到職員davy jones的記錄,用戶可以輸入如下語句:

  select * from employees

  where last_name = ''jones'' and first_name = ''davy'';

  在本例中,我們通過邏輯連接符and將兩個(gè)斷言連接起來。只有兩個(gè)斷言都滿足時(shí)整個(gè)表達(dá)式才會(huì)滿足。如果用戶需要定義一個(gè)select語句來使得當(dāng)其中任何一項(xiàng)成立就滿足條件時(shí),可以使用or連接符:

  select * from employees

  where last_name = ''jones'' or last_name = ''smith'';

  有時(shí)定義一個(gè)斷言的最好方法是通過相反的描述來說明。如果你想要查看除了boston辦事處的職員以外的其他所有職員的信息時(shí),你可以進(jìn)行如下的查詢:

  select * from employees

  where not(branch_office = ''boston'');

  關(guān)鍵字not后面跟著用圓括號括起來的比較表達(dá)式。其結(jié)果是對結(jié)果取否定。如果某一職員所在部門的辦事處在boston,括號內(nèi)的表達(dá)式返回true,但是not操作符將該值取反,所以該行將不被選中。

  斷言可以與其他的斷言嵌套使用。為了保證它們以正確的順序進(jìn)行求值,可以用括號將它們括起來:

  select * from employees

  where (last_name = ''jones''

  and first_name = ''indiana'')

  or (last_name = ''smith''

  and first_name = ''bessie'');

  sql沿用數(shù)學(xué)上標(biāo)準(zhǔn)的表達(dá)式求值的約定—圓括號內(nèi)的表達(dá)式將最先進(jìn)行求值,其他表達(dá)式將從左到右進(jìn)行求值。