跟我学SQL一数据查询.docx
《跟我学SQL一数据查询.docx》由会员分享,可在线阅读,更多相关《跟我学SQL一数据查询.docx(40页珍藏版)》请在冰豆网上搜索。
跟我学SQL一数据查询
跟我学SQL:
(一)数据查询
且不说你是否正在从事编程方面的工作或者不打算学习SQL,可事实上几乎每一位开发者最终都会遭遇它。
你多半还用不着负责创建和维持某个数据库,但你怎么着也该知道以下的一些有关的SQL知识。
我为那些感兴趣的开发者或者能从数据库操作中得益的读者撰写了这篇关于基本SQL语法的概述性文章。
本文主要讨论基本的数据操作查询,后续的文章还会继续讨论如何修改数据库自身以及更高级的查询概念。
SQL数据库是怎么回事?
SQL(结构化查询语言)就是负责与ANSI维护的数据库交互的标准。
最新的版本是SQL-99,还有一个新标准SQL-200n尚处于制定过程中。
大多数的数据库都至少遵守ANSI-92标准的部分子集。
不过,目前对最新标准的有效性还存在一些争论。
专有数据库制造商根据这些标准开发自己的产品,同时制定出自己特有的数据库存储操作新概念。
几乎各种不同的数据库都包含了自己特有的语法集合,只是通常很类似ANSI标准。
在大多数情况下,尽管有一些数据库实例基于特定的扩展语法会因数据库的不同而产生不同的结果,但总的说来,这些新加的语法不过是对原有标准的扩充。
如果数据库操作并没有得到你希望的结果,那么你不妨事先读一读数据库制造商提供的产品说明。
假如到目前为止你头回遭遇SQL语言,那么你怎么也得先理解一些基本的SQL概念。
我尽量把这些基本知识阐述得简明扼要,如果你对那些数据库术语还能忍受,你尽可跳到下一节,此外你还可以把自己的问题提交给以下的讨论区。
笼统地说,“SQL数据库”其实就是关系型数据库管理系统(RDMS)通俗的叫法。
对某些系统来说,“数据库”也指一组数据表、数据以及相互区分但结构类似的配置信息。
在这种情况下,每一SQL数据库的安装都可能由若干数据库组成。
在有些系统上,这种数据库则指的是表空间。
数据表是一种包含多行数据的数据库构造,这种数据库构造由命名的列组成。
通常数据表构造为包含关系信息,同一数据库或表空间以内可以创建若干数据表。
表内的列保存某一种类型的数据而且应根据其保存数据的内容得以命名。
例如,被称为“LastName”的列就应该在每一行包含姓氏条目。
正是这一前提的存在才能让关系数据库查询返回一致的结果。
字段(field)指的是某一行某一列对应的数据(或保存数据的地方)。
另外,数据集合(dataset)则指的是多行多列的数据,而且数据集合通常说明你的数据库或数据表内的全部数据。
结果集合(resultset)就是从数据库查询返回的数据;它能够描述从单一字段到数据库内全部数据这一范围内的全部信息。
数据库查询就是发送给数据库的SQL指令,这些指令向数据库请求某种施加在数据集合或数据库上的功能。
现在我们就来看看基本的数据库查询,这些查询主要涉及到对数据库内数据的操作。
在本文中,所有的例子都采用了标准SQL语言,而且这些基本功能可以转换为应用在几乎各种环境下。
数据查询类型
SQL语言中的数据查询分为4种基本类型:
SELECT:
这条语句要求数据库返回指定结果的数据集合;你可以用这一语句检索数据库中保存的信息。
INSERT:
这条语句用来给数据表增加新一行数据。
DELETE:
该语句从你的数据库中删除若干行数据。
UPDATE:
该语句修改数据库内的现有数据。
以上的这些语句都有各种各样的限定词和函数供你用来定义有关的数据集合,同时控制查询返回的结果集合。
SELECT语句的选项最多。
有许多种组合SELECT的查询选项,例如JOIN和UNION等。
不过就我们目前来说,本文主要还是关注基本用途。
用SELECT语句检索保存的信息
为了获得数据库中保存的信息就必须采用SELECT语句。
其基本功能限制在针对单一数据表操作,当然,其他范围的构造也是有的。
为了返回特定列所对应的所有数据行,你可以使用以下语句:
SELECTcolumn1,column2FROMtable_name;
另外,使用通配符“*”可以从表中选出所有的列:
SELECT*FROMtable_name;
你要愿意自己编码分析以上返回的结果当然也没问题,不过你完全可以采用方便的WHERE子句限制返回的结果集合,该子句可以让你为选择数据定义某些条件。
以下查询就会返回“column1”数值等于3的所以数据行:
SELECT*FROMtable_nameWHEREcolumn1=3;
除了“=”(等于)条件之外你还可以用到下列条件运算符:
表A
=等于
<>不等于
>大于
<小于
>=大于或等于
<=小于或等于
SQL条件语句
另外,你还可以联合WHERE语句使用BETWEEN、LIKE等比较运算符以及AND和OR这类逻辑运算符。
注意,OR语句是包含性的的。
以下有一个例子组合了以上这些概念:
SELECT*FROMtable_nameWHERE((Age<18)AND(LastNameBETWEEN‘Anderson’AND‘Miller’))ORCompanyLIKE‘%School%’;
用自然语言来说,这条选择语句的含义是这样的:
从数据表中选出年龄小于18岁而且姓氏在“Anderson”和“MIller”之间的或者其公司名称类中有“School”字样的数据行。
用INSERT语句加入新数据
使用INSERT语句可以创建新的数据行。
如果你希望在某一行的某个字段中赋值则要用到UPDATE语句。
插入语句的语法如下:
INSERTINTOtable_name(column1,column2,column3)
VALUES(‘data1’,‘data2’,‘data3’);
如果你想按照表内现有列的同一顺序插入所有的值,那么你不必指定列名,当然,从可读性考虑最好不要这样做。
另外,如果你列出列名则不必要按照它们在数据库中出现的顺序包括它们,只要你列出的值与它们一一对应即可。
有些列你并没有为其输入新的信息所以你自然没有必要列出它们来。
一旦数据库中有了数据要修改起来也与此很相似。
UPDATE语句和WHERE子句
UPDATE用来修改现有的值或行里的空字段,因此它必须在匹配现有的数据集合同时提供可接受的值。
除非你真地想要修改所有数据行上的值,否则你必须使用WHERE子句。
UPDATEtable_nameSETcolumn1=‘data1’,column2=‘data2’
WHEREcolumn3=‘data3’;
你可以采用WHERE子句随意匹配任何一列,正在修改的一列都可以。
这样会有助于你把某一特定的值修改为另一个值:
UPDATEtable_nameSETFirstName=‘Shelley’
WHEREFirstName=‘Shelly’ANDLastName=‘Doll’;
小心DELETE语句
DELETE语句会从数据库的数据表中删除整行。
如果你仅仅想删除单一的字段则应该使用UPDATE语句把它修改为代表应用程序中的NULL的其他空值。
一定要小心使用带WHERE子句的DELETE语句,否则你可能会遭遇清空全部数据表的风险。
DELETEFROMtable_nameWHEREcolumn1=‘data1’;
一旦你数据库中删除某一行数据就不可再后悔了,因此一般来说,最好在数据表中包括一名为“IsActive”的列或类似的指示信息,这样你就可以把该列数据设置为零表示数据禁用。
只有在你确信不再需要受到影响的信息之后你才可以用DELETE语句。
小结
SQL就是数据库的语言,我们已经了解了数据查询中所采用的最基本命令语句。
但还有很多基本概念尚未涉及,例如SUN和COUNT函数等,但以上列出的这些命令应该足够你开始着手数据库操作了。
跟我学SQL:
(二)SELECT语句选项
跟我学SQL分为三部分,其中涵盖了有关SQL标准的基本知识。
在上一篇文章里我们讨论了一些数据库术语和4种最基本的数据查询类型。
此外,我们还解释了WHERE子句和条件语句的用法,同时我们提供了各类查询的具体示例。
在这篇文章里,我们将就其他一些SQL函数和子句进行阐述,供你用于基本的SELECT数据查询中。
SELECT选项精制结果
正如我们从上一篇文章中所读到的那样,SELECT语句具有种类繁多的各类选项,这些选项可以用来控制数据返回的方式。
这些选项以子句、关键词和函数的形式存在。
子句是一种修改结果的语句。
子句不是必要的语句但它对数据的内容及其显示进行了提炼。
WHERE子句就是这样的子句。
关键词触发数据库的内在功能。
这些关键词在有时甚至是查询所必需的。
例如“INSERTINTOtable_name(column1)VALUES(‘data1’);”语句中的INTO和VALUE就是如此。
我们将了解DISTINCT关键词,它能触发一些非常有用的可选功能。
下面总结了一些最常用的子句、关键词和函数。
然后我会对每一部分举例说明。
ORDERBY–按照指定列排序返回结果的子句
DISTINCT–只返回结果集合内唯一行的关键词
COUNT--返回匹配查询的数据行总数数值的函数
AVG–该函数返回指定列的平均值
SUM–该函数把指定的列中的数字加起来
MIN–该函数返回列中最小的非NULL值
MAX–该函数返回列中的最大值
GROUPBY–按列汇集查询函数结果的子句
用ORDERBY对查询结果排序
ORDERBY子句让数据库对查询结果排序,这样你就无须自己编写应用程序进行“手工”排序了。
ORDERBY子句必须放在查询语句的结尾。
其基本用法如下:
SELECT*FROMContactsORDERBYfirst_name;
你可以随意在任何选择语句中使用ORDERBY子句返回多列结果。
你还可以用它连接其他子句:
SELECTfirst_name,last_nameFROMContactsWHEREfirst_nameBETWEEN‘a’AND‘k’ORDERBYlast_name;
你可以对多列数据排序。
优先顺序按从左到右依次降低,所以查询语句中各列的排列顺序很重要。
SELECT*FROMContactsORDERBYcompany,last_name,first_name;
查询结果默认按数字或者字母的升序排序。
你可以在ORDERBY子句后面加上DESC关键词改成降序排列。
在下面的例子中,最高的net_amount排在最先(降序)。
假如两行或者两行以上数据都包含了同样的net_amount值,那么同行中last_name值在字母表中最先出现的排先,因为last_name一列还是按照升序排序的。
SELECT*FROMSalesORDERBYnet_amountDESC,last_name,first_name;
在按照定义的列名排序以后,大多数数据库随后将按照数据表内的第一列排序然后顺序向右再排序。
具体的实现各有变化,因此,如果排序在应用中比较重要那么你应该明确地定义所要排序的列。
另外一值得注意的问题是,采用ORDERBY子句(以及WHERE子句),你正在用来排序结果的数据列并不一定得是返回结果集合的一部分。
只要所有引用的列都在数据表内存在则下例完全有效:
SELECTcompany,first_name,net_amountFROMSalesORDERBYstart_date,last_name;
DISTINCT返回不重复结果
DISTINCT关键词只返回结果集合内不重复的数据行。
例如,有时你可能需要找出Sales表内的公司,但是你又不想看见每个条目。
于是你可以用DISTINCT对应每一公司名返回一行数据:
SELECTDISTINCTcompanyFROMSales;
在使用DISTINCT时,它适用于所有的请求列。
如果你打算列出表内的所有销售人员和他们所代表的公司而非每一销售记录,那么你可以使用下列语句。
注意,这样操作还可能返回同一公司的若干条目等等。
SELECTDISTINCTcompany,last_name,first_nameFROMSales;
你还可以在对结果缩小范围和进行排序时结合SELECT语句使用DISTINCT。
为了确定显示的内容,数据库首先会证实精练的请求是否匹配数据行,然后应用DISTINCT功能。
在全部结果集合都得以确定之后即处理ORDERBY子句。
如下例所示,只有net_amount大于100的数据行才被返回。
由于DISTINCT保留遇见的第1个匹配查询条件的数据行而丢弃其他匹配行,所以ORDERBY语句所引用的net_amount看起来就好象产生了随机的结果。
SELECTDISTINCTcompany,last_name,first_nameFROMSalesWHEREnet_amount>100ORDERBYcompany,net_amount;
函数应用逻辑
返回单一值的函数称做聚集函数(aggregatefunction)。
通过应用程序访问下列聚集函数的结果时,包含结果的“字段名”就是你所使用的实际函数。
例如,在分析你的数据库结果时,结果数组的键值可能如下所示:
$keyname=“COUNT(*)”;
$resultkey=“AVG(net_amount)”;
COUNT
COUNT函数计算出结果集合中的数据行数。
和其他函数一样它接受一个参数。
以下的基本示例能告诉你数据表内的行数:
SELECTCOUNT(*)FROMSales;
你也可以用它来计算任何结果集合中的行数。
SELECTCOUNT(*)FROMSalesWHEREnet_amount>100;
如果你想看看某特定列有多少行包含非空值,那你不妨对该列使用COUNT函数。
注意,除非数据库设置为字段为空时缺省填充NULL否则将返回表内数据行的总数。
另外,列出的列在超出一个的情况下会引起错误。
SELECTCOUNT(company)FROMSales;
COUNT还可以用来计算DISTINCT结果集合中的行数。
SELECTCOUNT(DISTINCTcompany,last_name)FROMSales;
COUNT语句通常用在程序中确定FOR循环的循环次数。
AVG
AVG返回某列所有字段的平均值,该列必须是数字数据类型。
该函数用列的名字作为其参数,如果列字段数据类型是非数字类型的则函数返回“0”。
SELECTAVG(net_amount)FROMSales;
你可以结合子句限制该函数的应用范围。
SELECTAVG(net_amount)FROMSalesWHEREcompanyLIKE‘%ABCDCo%’;
就象所有聚集函数一样,ORDERBY语句将被忽略。
SUM
SUM的工作方式和AVG差不多,只不过该函数返回结果集合中所有字段值的和。
SELECTSUM(net_amount)FROMSalesWHEREnet_amount>100;
AVG、SUM、MIN和MAX函数在没有指定列的情况下都会返回错误,所以你不能使用“*”通配符。
MIN
MIN返回指定列中最小的非空值。
如果指定列是数字数据类型则结果将是最小的数字。
如果它是一种字符串数据类型则函数将返回按字母表顺序出现的第1个值。
SELECTMIN(net_amount)FROMSalesWHERElast_name=“Smith”;
SELECTMIN(last_name)FROMSales;
MAX
MAX的工作方式和MIN函数一样,只不过该函数返回最大的非空值。
该函数也可以用于字符串或者数字列
SELECTMAX(net_amount)FROMSales;
SELECTMAX(company)FROMSalesWHEREnet_amount>100;
MAX函数有时还用在包含自动递增键字段的列上确定下一条目的键ID。
除非你正在运行一个非公开的数据库,否则在使用这一信息插入下一条目时务必谨慎,以防其他用户先你执行数据操作。
GROUPBY令函数更有用
虽然以上提到的所有这些函数都能提供相当有用的信息,但是,如果有GROUPBY子句帮忙的话更能让你在列的字段子集中应用这些函数。
不要对你的Sales表中每一家公司一次又一次地执行MAX函数查询——你完全可以带GROUPBY子句获得同样的结果:
SELECTcompany,MAX(net_amount)FROMSalesGROUPBYcompany;
这样做可以获得每家公司net_amount的的最大值。
在选择多列名的时候也可以采用该语句,你还可以用多列来对函数结果分组。
下面的例子演示了以上各种方式。
首先,包括GROUPBY子句可以令你指定要显示的其他列。
然而,你得知道这个例子将返回在组中遇到的第1个last_name值;Sum(net_amount)将显示全部公司的结果而不仅仅针对匹配姓氏的数据行。
这是因为,我们只使用了Company字段来定义我们的组。
SELECTcompany,last_name,SUM(net_amount)FROMSalesGROUPBYcompany;
在上面的例子中,last_name列实际上并没有提供什么有用的信息,但这样做是为了在下一个例子中要用到的功能做准备。
你可以创建多列定义的组。
这样就可以在结果集合中产生针对特定行的函数结果,而结果集合则是由所有指定的GROUPBY列联合起来创建的:
SELECTcompany,AVG(net_amount),last_nameFROMSalesGROUPBYcompany,last_name;
上面的例子给每家公司中每一姓氏给出了平均的net_amount。
你列出GROUPBY列的顺序控制着结果的排序,但是实际的函数值结果是一样的。
下面的例子表明如何组织结果而不显示分组的列。
在有些场合这样做是很有用的,例如,如果要显示个人的销售量但却不显示姓名就能用上下面的例子了:
SELECTcompany,COUNT(sale_id)FROMSalesGROUPBYcompany,last_name;
限制使用GROUPBY的查询
如你在以上示例中所看到的那样,你可以结合WHERE字句利用以上的概念限制查询的范围。
WHERE子句会首先被计算,然后执行函数。
在使用组的时候就是这样的。
SELECTcompany,AVG(net_amount),FROMSalesWHEREnet_amount>100GROUPBYcompany;
上面的例子只对那些满足WHERE限制条件的数据行适用AVG函数。
注意,WHERE子句必须放在GROUPBY子句之前。
你还可以用HAVING语句对分组计算之后限制返回的结果集合。
SELECTcompany,AVG(net_amount),FROMSalesWHERElast_nameBETWEEN‘a’AND‘m’GROUPBYcompanyHAVINGAVG(net_amount)>500;
上面的语句计算每家公司net_amount的平均值,而且只计算那些姓氏满足限制条件的销售人员的销售量,同时只显示大于500的结果。
跟我学SQL:
(三)使用SQL子选择来合并查询
你是否曾经为了得到所需要的信息而反复查询?
子选择,也被称为子查询,也许正是你在寻找的。
SQL的这项功能使你可以在一组结果中查询,创造性地给结果组加以限定,或是在向数据库的单一调用中将结果与一个无关系的查询做相关。
这篇文章中我将给出几个子选择的例子并就何时使用他们进行讨论。
在一个结果组中搜索
子选择的理念很简单:
一个选择查询安置在另一个查询内部,创建一个在单一声明搜索中不可用的资源。
子选择允许查询的合并,结果组比较的责任落到了数据库中而不是应用软件代码中。
使用这个功能的一个途径是对两个表格中的可比数据专栏中的值进行定位。
例如,我的一个数据库有两个表格,Album和Lyric。
我可以很容易地通过下面的子查询声明来找到每一个Metallica的歌曲中包含“justice”的歌名:
SELECTsong_nameFROMAlbum
WHEREband_name=‘Metallica’
ANDsong_nameIN
(SELECTsong_nameFROMLyric
WHEREsong_lyricLIKE‘%justice%’);
这个例子是很简单的,我从Album表格中选择了所有Metallica的歌曲,接着,我在lyric表格中选择所有包含“justice”的歌曲,最后,我使用IN关键字来从Lyric表格结果组中显示的Album表格中返回歌曲名称。
我使用Lyric表格结果组来给Album表格中的结果做限定。
WHERE子句中的子选择部分是完全自包含的,因此我不需要使用例如Album.song_name和Lyric.song_name等完整的专栏名称。
我没有从最终结果组的Lyric表格中返回任何值,如果我需要歌曲的Lyric,我会使用一个JOIN声明。
使用NOTIN排除结果
你可以使用NOTIN关键字来获得明确地不被包含在另一个结果组中的结果。
例如,我想要通过下面的代码来返回Metallica在“AndJusticeforAll”专辑中不包含单词“justice”的歌曲:
SELECTsong_nameFROMAlbum
WHEREalbum_name=‘AndJusticeforAll’
ANDband_name=‘Metallica’
ANDsong_nameNOTIN
(SELECTsong_nameFROMLyric
WHEREsong_lyricLIKE‘%justice%’);
在前面的SQL代码中,我选择了Metallica的“AndJusticeforAll,”专辑中的所有歌曲,接着是带有歌词中带有“justice”所有歌曲,最后从在Lyric结果组中没有出现的Album结果组返回了所有歌曲。
较之于返回两个查询并使用代码来比较数组,你通过一个单独的声明就可以得到确切的结果。
使用EXISTS来相关结果
有时你可以通过多种途径来访问相同的数据,而且你需要对你的结果进行匹配(或相关)来得到值的交叉区。
例如,我可以通过搜索Album表格来得到Metallica的歌曲列表,可是,我也可以从我的Cover表格中得到由Damage,Inc表演的Metallica的歌曲的列表,我可以在两个表格中直接比较查询结果来对值作相关。
SELECTAlbum.song_nameFROMAlbum
WHEREAlbum.band_name=‘Metallica’
ANDEXISTS
(SELECTCover.song_nameFROMCover
WHERECover.band_name=‘Damage,Inc.’
ANDCover.song_name=Album.song_name);
在SQL代码中,我使用完整的专栏名称,这是因为我直接对两个表格作比较,而不仅仅是