【网学网提醒】:以下是网学会员为您推荐的SQL中的select(zero),希望本篇文章对您学习有所帮助。
SQL里面最常用的命令是SELECT语句,用于检索数据。语法是:
SELECT[ALL|DISTINCT[ON(expression[,...])]]*|expression[ASoutput_name][,...][INTO[TEMPORARY|TEMP][TABLE]new_table][FROMfrom_item[,...]][WHEREcondition][GROUPBYexpression[,...]][HAVINGcondition[,...]][{UNION|INTERSECT|EXCEPT[ALL]}select][ORDERBYexpression[ASC|DESC|USINGoperator][,...]][FORUPDATE[OFclass_name[,...]]][LIMIT{count|ALL}[{OFFSET|,}start]]
现在我们将通过不同的例子演示SELECT语句复杂的语法。用于这些例子的表在供应商和
部件数据库里定义。
1.4.1.1.简单的Select
这里是一些使用SELECT语句的简单例子:Example1-4.带有条件的简单查询要从表PART里面把字段PRICE大于10的所有记录找出来,我们写出下面查询:
SELECT*FROMPARTWHEREPRICE>10;
然后得到表:
PNO|34||
PNAMEBoltCam
|||
PRICE1525
-----+---------+--------
在SELECT语句里使用"*"将检索出表中的所有属性。如果我们只希望从表PART中检索出属性PNAME和PRICE,我们使用下面的语句:
SELECTPNAME,PRICEFROMPARTWHEREPRICE>10;
这回我们的结果是:
PNAMEBoltCam
|||
PRICE1525
--------+--------
请注意SQL的SELECT语句对应关系演算里面的"projection"(映射)而不是"selection",(选择)(参阅关系演算获取详细信息)。
WHERE子句里的条件也可以用关键字OR,AND,和NOT逻辑地连接起来:逻辑地连接起来:,,
SELECTPNAME,PRICEFROMPARTWHEREPNAME='Bolt'AND(PRICE=0ORPRICE<=15);
这样将生成下面的结果:
PNAMEBolt
||
PRICE15
--------+--------
子句里可以使用算术操作。目标列表和WHERE子句里可以使用算术操作。例如,如果我们想知道如果我们买两个部件的话要多少钱,我们可以用下面的查询:
SELECTPNAME,PRICE*2ASDOUBLEFROMPART
WHEREPRICE*2<50;
这样我们得到:
PNAMEScrewNutBolt
||||
DOUBLE201630
--------+---------
请注意在关键字AS后面的DOUBLE是第二个列的新名字。这个技巧可以用于目标列表里的每个元素,给它们赋予一个在结果列中显示的新的标题。这个新的标题通常称为别名。这个别名不能在该查询的其他地方使用。
1.4.1.2.Joins(连接)(连接)
下面的例子显示了SQL里是如何实现连接的。要在共同的属性上连接三个表SUPPLIER,PART和SELLS,我们通常使用下面的语句:
SELECTS.SNAME,P.PNAMEFROMSUPPLIERS,PARTP,SELLSSEWHERES.SNO=SE.SNOANDP.PNO=SE.PNO;
而我们得到的结果是:
SNAME|PNAME-------+------Smith|ScrewSmith|NutJones|CamAdams|ScrewAdams|BoltBlake|NutBlake|Bolt
Blake|Cam
在FROM子句里,我们为每个关系使用了一
个别名,因为在这些关系间有着公共的命名属性(SNO和PNO)。现在我们可以区分不同表的公共命名属性,只需要简单的用每个关系的别名加上个点做前缀就行了。联合是用与一个内部联接里显示的同样的方法计算的。首先算出笛卡儿积SUPPLIER×PART×SELLS。然后选出那些满足WHERE子句里给出的条件的记录(也就是说,公共命名属性的值必须相等)。最后我们映射出除S.SNAME和P.PNAME外的所有属性。另外一个进行连接的方法是使用下面这样的SQLJOIN语法:
selectsname,pnamefromsupplierJOINsellsUSING(sno)JOINpartUSING(pno);
givingagain:
sname|pname-------+------Smith|ScrewAdams|ScrewSmith|NutBlake|NutAdams|BoltBlake|BoltJones|CamBlake|Cam(8rows)
一个用JOIN语法创建的连接表,是一个出现在FROM子句里的,在任何WHERE,GROUPBY或HAVING子句之前的表引用列表项.其它表引用,包括表名字或者其它JOIN子句,如果用逗号分隔的话,可以包含在FROM子句里.连接生成的表逻辑上和任何其它在FROM子句里列出的表都一样.
SQLJOIN有两种主要类型,CROSSJOIN(无条件连接)和条件连接.条件连接还可以根据声明的连接条件(ON,USING,或NATURAL)和它应用的方式(INNER或OUTER连接)进一步细分.
连接类型CROSSJOIN{T1}CROSSJOIN{T2}一个交叉连接(crossjoin)接收两个分别有N行和M行的表T1和T2,然后返回一个包含交叉乘积NxM条记录的连接表.对于T1的每行R1,T2的每行R2都与R1连接生成连接的表行JR,JR包含所有R1和R2的字段.CROSSJOIN实际上就是一个INNERJOINONTRUE.条件JOIN{T1}[NATURAL][INNER|{LEFT|RIGHT|FULL}[OUTER]]JOIN{T2}{ONsearch
condition|USING(joincolumnlist)}
一个条件JOIN必须通过提供一个(并且只能有一个)NATURAL,ON,或者USING这样的关键字来声明它的连接条件.ON子句接受一个search
condition,它与一个WHERE子句相同.USING子句接受一个用逗
号分隔的字段名列表,连接表中必须都有这些字段,并且用那些字段连接这些表,生成的连接表包含每个共有字段和两个表的所有其它字段.NATURAL是USING子句的缩写,它列出两个表中所有公共的字段名字.使用USING和NATURAL的副作用是每个连接的字段都只有一份拷贝出现在结果表中(与前面定义的关系演算的JOIN相比较).
[INNER]JOIN对于T1的每行R1,连接成的表在T2里都有一行满足与R1一起的连接条件.对于所有JOIN而言,INNER和OUTER都是可选的.INNER是缺省.LEFT,RIGHT,和FULL只用于OUTERJOIN.
LEFT[OUTER]JOIN首先,执行一次INNERJOIN.然后,如
果T1里有一行对任何T2的行都不满足连接条件,那么返回一个连接行,该行的T2的字段为null.小技巧:连接成的表无条件地包含T1里的所有行.小技巧RIGHT[OUTER]JOIN首先,执行一次INNERJOIN.然后,如果T2里有一行对任何T1的行都不满足连接条件,那么返回一个连接行,该行的T1的字段为null.小技巧:小技巧连接成的表无条件地包含T2里的所有行.FULL[OUTER]JOIN首先,执行一次INNERJOIN.然后,如果T1里有一行对任何T2的行都不满足连接条件,那么返回一个连接行,该行的T1的字段为null.同样,如果T2里有一行对任何T1的行都不满足连接条件,那么返回一个连接行,该行的T2的字段为null.小技巧:小技巧连接成的表无条件地拥有来自T1的每一行和来自T2的每一行.所有类型的JOIN都可以链接在一起或者嵌套在一起,这时T1和T2都可以是连接生成的表.我们可以使用圆括弧控制JOIN的顺序,如果我们不主动控制,那么连接顺序是从左到右.
1.4.1.3.聚集操作符
SQL提供以一些聚集操作符(如,AVG,COUNT,SUM,MIN,MAX),这些聚集操作符以一个表达式为参数。只要是满足WHERE子句的行,就会计算这个表达式,然后聚集操作符对这个输入数值的集合进行计算.通常,一个聚集对整个SELECT语句计算的结果是生成一个结果.但如果在一个查询里面声明了分组,那么数据库将对每个组进行一次独立的计算,并且聚集结果是按照各个组出现的(见下节).Example1-5.聚集果我们想知道表PART里面所有部件的平均价格,我们可以使用下面查询:
SELECTAVG(PRICE)ASAVG_PRICE
FROMPART;
结果是:
AVG_PRICE----------14.5
如果我们想知道在表PART里面存储了多少部件,我们可以使用语句:
SELECTCOUNT(PNO)FROMPART;
得到:
COUNT------41.4.1.4.分组聚集
SQL允许我们把一个表里面的记录分成组。然后上面描述的聚集操作符可以应用于这些组上(也就是说,聚集操作符的值不再是对所有声明的列的值进行操作,而是对一个组的所有值进行操作。这样聚集函数是为每个组独立地进行计算的。)对记录的分组是通过关键字GROUPBY实现的,GROUPBY后面跟着一个定义组的构成的属性列表。如果我们使用语句GROUPBYA1,&;tdot;,Ak我们就把关系分成了组,这样当且仅当两条记录在所有属性A1,&;tdot;,Ak上达成一致,它们才是同一组的。Example1-6.聚集如果我们想知道每个供应商销售多少个部件,我们可以这样写查询:
SELECTS.SNO,S.SNAME,COUNT(SE.PNO)FROMSUPPLIERS,SELLSSEWHERES.SNO=SE.SNO
GROUPBYS.SNO,S.SNAME;
得到:
SNO|SNAME|COUNT-----+----
---+------1234|Smith||Jones||Adams||Blake|2123
然后我们看一看发生了什么事情。首先生成表SUPPLIER和SELLS的连接:
S.SNO|S.SNAME|SE.PNO-------+---------+-------11233444||||||||SmithSmithJonesAdamsAdamsBlakeBlakeBlake||||||||12413234
然后我们把那些属性S.SNO和S.SNAME相同的记录放在组中:
S.SNO|S.SNAME|SE.PNO-------+---------+-------1|Smith||2|Jones|124
---------------------------------------------------
3
|
Adams
||
13234
-------------------------4|Blake|||
在我们的例子里,我们有四个组并且现在我们可以对每个组应用聚集操作符COUNT,生成上面给出的查询的最终结果。
请注意如果要让一个使用GROUPBY和聚集操作符的查询的结果有意义,那么用于分组的属性也必须出现在目标列表中。所有没有在GROUPBY子句里面出现的属性都只能通过使用聚集函数来选择。否则就不会有唯一的数值与其它字段关联.还要注意的是在聚集上聚集是没有意义的,比如,AVG(MAX(sno)),因为SELECT只做一个回合的分组和聚集.你可以获得这样的结果,方法是使用临时表或者在FROM子句中使用一个子SELECT做第一个层次的聚集.
1.4.1.5.Having
HAVING子句运做起来非常象WHERE子句,只用于对那些满足HAVING子句里面给出的条件的组进行计算。其实,WHERE在分组和聚集之前过滤掉我们不需要的输入行,而HAVING在GROUP之后那些不需要的组.因此,WHERE无法使用一个聚集函数的结果.而另一方面,我们也没有理由写一个不涉及聚集函数的HAVING.如果你的条件不包含聚集,那么你也可以把它写在WHERE里面,这样就可以避免对那些你准备抛弃的行进行的聚集运算.Example1-7.Having如果我们想知道那些销售超过一个部件的供应商,使用下面查询:
SELECTS.SNO,S.SNAME,COUNT(SE.PNO)FROMSUPPLIERS,SELLSSEWHERES.SNO=SE.SNO
GROUPBYS.SNO,S.SNAMEHAVINGCOUNT(SE.PNO)>1;
andget:
SNO|SNAME|COUNT-----+-------+------134|Smith||Adams||Blake|223
1.4.1.6.子查询
在WHERE和HAVING子句里,允许在任何要产生数值的地方使用子查询(子选择)。这种情况下,该值必须首先来自对子查询的计算。子查询的使用扩展了SQL的表达能力。Example1-8.子查询如果我们想知道所有比名为'Screw'的部件贵的部件,我们可以用下面的查询:
SELECT*FROMPARTWHEREPRICE>(SELECTPRICEFROMPARTWHEREPNAME='Screw');为比较条件.&;&;子查询实际确定一个记录,作
结果是:
PNO|34||
PNAMEBoltCam
|||
PRICE1525
-----+---------+--------
当我们检查上面的查询时会发现出现了两次SELECT关键字。第一个在查询的开头-我们将称
之为外层SELECT-而另一个在WHERE子句里面,成为一个嵌入的查询-我们将称之为内层SELECT。对外层SELECT的每条记录都必须先计算内层SELECT。在完成所有计算之后,我们得知名为'Screw'部件的记录的价格,然后我们就可以检查那些价格更贵的记录了。(实际上,在本例中,内层查询只需要执行一次,因为它不依赖于外层查询高等状态.)如果我们想知道那些不销售任何部件的供应商(比如说,我们想把这些供应商从数据库中删除),我们用:
SELECT*FROMSUPPLIERSWHERENOTEXISTS(SELECT*FROMSELLSSEWHERESE.SNO=S.SNO);
在我们的例子里,结果列将是空的,因为每个供应商至少销售一个部件。请注意我们在WHERE子句的内层SELECT里使用了来自外层SELECT的S.SNO。正如前面所说的,子查询为每个外层查询计算一次,也就是说,S.SNO的值总是从外层SELECT的实际记录中取得的。
1.4.1.7.在FROM里面的子查询
一种有些特别的子查询的用法是把它们放在FROM子句里.这个特性很有用,因为这样的子查询可以输出多列和多行,而在表达式里使用的子查询必须生成一个结果.FROM里的子查询还可以让我们获得多于一个回合的分组/聚集特性,而不需要求助于临时表.Example1-9.FROM里面的子查询如果我们想知道在所有我们的供应商中的最高平均部件价格的那家,我们不能用MAX(AVG(PRICE)),但我们可以这么写:
SELECTMAX(subtable.avgprice)FROM(SELECTAVG(P.PRICE)ASavgpriceFROMSUPPLIERS,PARTP,SELLSSEWHERES.SNO=SE.SNOANDP.PNO=SE.PNOGROUPBYS.SNO)subtable;
这个子查询为每个供应商返回一行(因为它的GROUPBY)然后我们在外层查询对所有行进行聚集.
1.4.1.8.Union,Intersect,Except(联合,相交,相异)(联合,相交,相异)
这些操作符分别计算两个子查询产生的元组的联合,相交和集合理论里的相异。Example1-10.Union,Intersect,Except下面的例子是UNION的例子:
SELECTS.SNO,S.SNAME,S.CITYFROMSUPPLIERSWHERES.SNAME='Jones'UNIONSELECTS.SNO,S.SNAME,S.CITYFROMSUPPLIERSWHERES.SNAME='Adams';
产生结果:
SNO|SNAME|23
CITY
-----+-------+-------|Jones|Paris|Adams|Vienna
下面是相交(INTERSECT)的例子:
SELECTS.SNO,S.SNAME,S.CITYFROMSUPPLIERSWHERES.SNO>1INTERSECTSELECTS.SNO,S.SNAME,S.CITYFROMSUPPLIERSWHERES.SNO<3;
产生结果:
SNO|SNAME|2
CITY
-----+-------+-------|Jones|Paris
两个查询都会返回的元组是那条SNO=2的
最后是一个EXCEPT的例子:
SELECTS.SNO,S.SNAME,S.CITYFROMSUPPLIERSWHERES.SNO>1EXCEPTSELECTS.SNO,S.SNAME,S.CITYFROMSUPPLIERSWHERES.SNO>3;
结果是:
SNO|SNAME|23
CITY
-----+-------+-------|Jones|Paris|Adams|Vien
na