资料

Mysql入门很简单.pdf 链接:https://pan.baidu.com/s/1SojegIqbWz8Dt8-iIjmJzA 
提取码:qt4a

数据库篇

SHOW DATABASES; //显示数据库系统中已经存在的数据库

CREATE DATABASE 数据库名; //创建数据库

DROP DATABASE 数据库名; //删除数据库

表篇

注:在使用操作表语句前,首先要使用USE语句选择数据库。选择数据库语句的基本格式为“USE 数据库名”。否则会报错,1046;

CREATE TABLE 表名 ( 属性名 数据类型 [完整性约束条件],
属性名 数据类型 [完整性约束条件],
属性名 数据类型
);
表名不能为SQL语句的关键字,一个表可以有多个属性。定义时,字母大小写均可,各属性之间用逗号隔开,最后一个属性不需要加逗号。

用程序创建表,可以使用SQL的CREATE TABLE语句。需要注意的是,使用交互式工具时实际上就是使用SQL语句。这些语句不是用户编写的,界面工具会自动生成并执行相应的SQL语句(更改已有的表时也是这样)。
利用CREATE TABLE创建表,必须给出下列信息:
  1. 新表的名字,在关键字CREATE TABLE之后给出;
  2. 表列的名字和定义,用逗号分隔;
  3. 有的DBMS还要求指定表的位置。

从上面的例子可以看到,表名紧跟CREATE TABLE关键字。实际的表定义(所有列)括在圆括号之中,各列之间用逗号分隔。这个表由5列组成。每列的定义以列名(它在表中必须是唯一的)开始,后跟列的数据类型,整条语句以圆括号后的分号结束
前面提到,不同DBMS的CREATE TABLE的语法有所不同,这个简单脚本也说明了这一点。
这条语句在Oracle、PostgreSQL、SQL Server和SQLite中有效,而对于MySQL, varchar必须替换为text;对于DB2,必须从最后一列中去掉NULL。这就是对于不同的DBMS,要编写不同的表创建脚本的原因(参见附录A)。

提示:
替换现有的表在创建新的表时,指定的表名必须不存在,否则会出错。防止意外覆盖已有的表,SQL要求首先手工删除该表(请参阅后面的内容),然后再重建它,而不是简单地用创建表语句覆盖它。

注意:理解NULL
不要把NULL值与空字符串相混淆。NULL值是没有值,不是空字符串。如果指定’'(两个单引号,其间没有字符),这在NOT NULL列中是允许的。空字符串是一个有效的值,它不是无值。NULL值用关键字NULL而不是空字符串指定。

指定默认值

SQL允许指定默认值,在插入行时如果不给出值,DBMS将自动采用默认值。默认值在CREATE TABLE语句的列定义中用关键字DEFAULT指定。


默认值经常用于日期或时间戳列。
例如,通过指定引用系统日期的函数或变量,将系统日期用作默认日期。MySQL用户指定DEFAULTCURRENT_DATE(), Oracle用户指定DEFAULT SYSDATE,而SQLServer用户指定DEFAULT GETDATE()。遗憾的是,这条获得系统日期的命令在不同的DBMS中几乎都是不同的。表17-1列出了这条命令在某些DBMS中的语法。这里若未列出某个DBMS,请参阅相应的文档。

提示:
使用DEFAULT而不是NULL值许多数据库开发人员喜欢使用DEFAULT值而不是NULL列,对于用于计算或数据分组的列更是如此。

更新表

更新表定义,可以使用ALTER TABLE语句。虽然所有的DBMS都支持ALTER TABLE,但它们所允许更新的内容差别很大。
以下是使用ALTERTABLE时需要考虑的事情。
  1. 理想情况下,不要在表中包含数据时对其进行更新。应该在表的设计过程中充分考虑未来可能的需求,避免今后对表的结构做大改动。□ 所有的DBMS都允许给现有的表增加列,不过对所增加列的数据类型(以及NULL和DEFAULT的使用)有所限制。
  2. 许多DBMS不允许删除或更改表中的列。
  3. 多数DBMS允许重新命名表中的列。
  4. 许多DBMS限制对已经填有数据的列进行更改,对未填有数据的列几乎没有限制。
可以看出,对已有表做更改既复杂又不统一。对表的结构能进行何种更改,请参阅具体的DBMS文档。使用ALTER TABLE更改表结构,必须给出下面的信息
  1. 在ALTER TABLE之后给出要更改的表名(该表必须存在,否则将出错);
  2. 列出要做哪些更改。

这条语句给Vendors表增加一个名为vend_phone的列,其数据类型为CHAR。

完整性约束条件


主键

主键有唯一值
单字段主键
属性名 数据类型 primary key //创建主键,写在属性名数据类型后面;
多字段主键
primary key(属性名 1,属性名2,属性名n)
两者的组合可以确定唯一的一条记录;

外键

外键不一定必须为父表的主键,但必须是唯一性索引,主键约束和唯一性约束都是唯一性索引;
外键可以为空值;

设置外键的基本语法规则如下:
CONSTRAINT 外键别名 FOREIGN KEY(属性 1.1,属性1.2,属性1.n)
REFERENCES 表名(属性2.1,属性2.2,属性2.n)
其中,“外键别名”参数是为外键的代号;“属性1”参数列表是子表中设置的外键;“表名”参数是指父表的名称;“属性2”参数列表是父表的主键。

设置表的非空约束

设置表的唯一性约束

设置表的属性值自动增加

查看表结构

DESCRIBE 表名; // 查看表基本结构语句,可缩写为desc 表名

SHOW CREATE TABLE 表名; //查看表详细结构语句 (包含存储引擎、字符编码)

删除表

DROP TABLE 表名;//删除没有被关联的普通表
删除父表需要先将外键删除,然后才能去删除父表。

字段篇

//通过ALTER TABLE语句

ALTER TABLE 旧表名 RENAME [TO] 新表名;//修改表名 TO参数是可选参数,是否在语句中出现不会影响语句的执行。

ALTER TABLE 表名 MODIFY 属性名 数据类型; //修改字段的数据类型(可以在此修改完整性约束条件)

ALTER TABLE 表名 CHANGE 旧属性名 新属性名 数据类型;//修改字段名和字段数据类型(两项都不可为空,都必须要填写,不然会报错)
MODIFY和CHANGE都可以改变字段的数据类型,不同的是,CHANGE可以在改变字段数据类型的同时,改变字段名。

ALTER TABLE 表名 ADD 属性名1 数据类型 [完整性约束条件] [FIRST | AFTER 属性名2]; //增加字段
属性名1为需要增加的字段的名称,完整性约束条件、FIRST、AFTER都是可选参数,FIRST、AFTER用来安排新字段的存放位置。否则默认为最后一个字段。

ALTER TABLE 表名 DROP 属性名;// 删除字段

ALTER TABLE 表名 MODIFY 属性名 数据类型 FIRST|AFTER 属性名2; //修改字段的排列位置

ALTER TABLE 表名 ENGINE = 存储引擎名; // 更改表的存储引擎
注:如果表中已经有很多的数据,改变引擎可能会造成意料之外的影响

ALTER TABLE 表名 DROP FOREIGN KEY 外键别名;//删除表的外键约束,其中,“外键别名“参数指创建表时设置的外键的代号。
查询(query)
任何SQL语句都是查询。但此术语一般指SELECT语句。
说明:
MySQL支持如果使用MySQL,应该知道对子查询的支持是从4.1版本引入的。MySQL的早期版本不支持子查询。

查询数据

1、基本查询语句

SELECT 属性表
FROM 表名和视图列表
[WHERE 条件表达式1]
[GROUP BY 属性名1 [HAVING 条件表达式2]]
[ORDER BY 属性名2 [ASC | DESC]]


"属性列表"参数表示查询的字段名;“表名和视图列表”参数表示从此处指定的表或者视图中查询数据,表和视图可以有多个;“条件表达式1”参数指定查询条件;“属性名1”参数指按该字段中的数据进行分组;“条件表达式2”参数表示满足该表达式的数据才能输出;“属性名2”参数指按该字段中的数据进行排序,排序方式由ASC和DESC两个参数指出;ASC参数表示按升序的顺序进行排序,这是默认参数;DESC参数表示按降序的顺序进行排序。

BETWEEN AND指定了某字段的取值范围; IN 指定了某字段的取值范围;IS NULL用来判断某字段的取值是否为空;ANDOR用来连接多个查询条件。

AS关键字

as是别名关键字,一般我们这么使用:select 字段 as 别名

IN关键字

IN关键字可以判断某个字段的值是否在指定的集合中。如果字段的值在集合中,则满足查询条件,该记录将被查询出来;

为什么要使用IN操作符?其优点如下。

  1.  在有很多合法选项时,IN操作符的语法更清楚,更直观。
  2.  在与其他AND和OR操作符组合使用IN时,求值顺序更容易管理。
  3.  IN操作符一般比一组OR操作符执行得更快(在上面这个合法选项很少的例子中,你看不出性能差异)。
  4.  IN的最大优点是可以包含其他SELECT语句,能够更动态地建立WHERE子句。
IN
WHERE子句中用来指定要匹配值的清单的关键字,功能与OR相当。

[NOT] IN (元素1,元素2,... ,元素n)
各元素之间用逗号隔开,字符型元素需要加上单引号。

NOT关键字

WHERE子句中的NOT操作符有且只有一个功能,那就是否定其后所跟的任何条件。因为NOT从不单独使用(它总是与其他操作符一起使用),所以它的语法与其他操作符有所不同。NOT关键字可以用在要过滤的列前,而不仅是在其后。
NOT
WHERE子句中用来否定其后条件的关键字。
为什么使用NOT?
对于这里的这种简单的WHERE子句,使用NOT确实没有什么优势。但在更复杂的子句中,NOT是非常有用的。
例如,在与IN操作符联合使用时,NOT可以非常简单地找出与条件列表不匹配的行

BETWEEN AND关键字可以判读某个字段的值是否在指定的范围内(包含起始值和终止值)。如果字段的值在指定范围内,则满足条件;

[NOT] BETWEEN 取值1 AND 取值2
“取值1”表示范围的起始值,“取值2”表示范围的终止值。

LIKE

关键字可以匹配字符串是否相等。

通配符(wildcard)

用来匹配值的一部分的特殊字符。
搜索模式(search pattern)
由字面值、通配符或两者组合构成的搜索条件。
通配符本身实际上是SQL的WHERE子句中有特殊含义的字符,SQL支持几种通配符。为在搜索子句中使用通配符,必须使用LIKE操作符。
LIKE指示DBMS,后跟的搜索模式利用通配符匹配而不是简单的相等匹配进行比较。

百分号(%)通配符

说明:请注意后面所跟的空格包括Access在内的许多DBMS都用空格来填补字段的内容。例如,如果某列有50个字符,而存储的文本为Fish bean bag toy(17个字符),则为填满该列需要在文本后附加33个空格。这样做一般对数据及其使用没有影响,但是可能对上述SQL语句有负面影响。子句WHEREprod_name LIKE 'F%y’只匹配以F开头、以y结尾的prod_name。如果值后面跟空格,则不是以y结尾,所以Fish bean bag toy就不会检索出来。简单的解决办法是给搜索模式再增加一个%号:'F%y%'还匹配y之后的字符(或空格)。更好的解决办法是用函数去掉空格

注:MySQL的搜索是不区分大小写的
 使用通配符的技巧正如所见,SQL的通配符很有用。但这种功能是有代价的,即通配符搜索一般比前面讨论的其他搜索要耗费更长的处理时间。这里给出一些使用通配符时要记住的技巧。
      1.  不要过度使用通配符。如果其他操作符能达到相同的目的,应该使用其他操作符。
      2.  在确实需要使用通配符时,也尽量不要把它们用在搜索模式的开始处。把通配符置于开始处,搜索起来是最慢的。
      3.  仔细注意通配符的位置。如果放错地方,可能不会返回想要的数据。总之,通配符是一种极其重要和有用的搜索工具,以后我们经常会用到它。
[NOT] LIKE '字符串'
“字符串”表示指定用来匹配的字符串,该字符串加单引号或者双引号。参数的值可以使一个完整的字符串,也可以是包含百分号(%)或者下划线(_)的通配符。
%”可以代表任意长度的字符串,长度可以为0;
_”只能表示单个字符。

IS NULL关键字用来判断字段的值是否为空值(NULL),如果字段的值为空值,则满足查询条件。

IS [NOT] NULL

AND关键字用来联合多个条件进行查询,只有同时满足所有条件的记录才会被查询出来。
条件表达式1 AND 条件表达式2 [...AND 条件表达式n]

OR关键字用来联合多个条件进行查询,但使用OR关键字时,只需要满足这几个查询条件的其中一个,就会被查询出来。
条件表达式1 OR 条件表达式2 [...OR 条件表达式n]

注:OR可以和AND一起使用。当两者一起使用时,AND要比OR先运算可以使用圆括号进行分割

消除重复结果

SELECT DISTINCT 属性名 // “属性名”参数表示要消除重复记录的字段的名词
eg: SELECT DISTINCT d_id FROM empliyee

对查询结果进行排序

ORDER BY 属性名 [ASC | DESC]
ASC(默认)表示按升序的顺序进行排序;DESC表示按降序的顺序进行排序;

要按多个列排序,简单指定列名,列名之间用逗号分开即可(就像选择多个列时那样)。下面的代码检索3个列,并按其中两个列对结果进行排序——首先按价格,然后按名称排序
SELECT prod_name,prod_price,prod_id /* 注释*/
FROM products
ORDER BY prod_price,prod_name
重要的是理解在按多个列排序时,排序的顺序完全按规定进行。换句话说,对于上述例子中的输出,仅在多个行具有相同的prod_price值时才对产品按prod_name进行排序。如果prod_price列中所有的值都是唯一的,则不会按prod_name排序。
警告:在多个列上降序排序如果想在多个列上进行降序排序,必须对每一列指定DESC关键字。
注意:ORDER BY子句的位置在指定一条ORDER BY子句时,应该保证它是SELECT语句中最后一条子句。
如果它不是最后的子句,将会出现错误消息。

WHERE字句操作符


注意:WHERE子句的位置在同时使用ORDER BY和WHERE子句时,应该让ORDER BY位于WHERE之后,否则将会产生错误(关于ORDER BY的使用,请参阅第3课)。

提示:何时使用引号如果仔细观察上述WHERE子句中的条件,会看到有的值括在单引号内,而有的值未括起来。单引号用来限定字符串。如果将值与字符串类型的列进行比较,就需要限定引号。用来与数值列进行比较的值不用引号。

空值检查

在创建表时,表设计人员可以指定其中的列能否不包含值。在一个列不包含值时,称其包含空值NULL
NULL无值(no value),它与字段包含0、空字符串或仅仅包含空格不同。
确定值是否为NULL,不能简单地检查是否= NULL。SELECT语句有一个特殊的WHERE子句,可用来检查具有NULL值的列。这个WHERE子句就是IS NULL子句。

注意:NULL和非匹配通过过滤选择不包含指定值的所有行时,你可能希望返回含NULL值的行。但是这做不到。因为未知(unknown)有特殊的含义,数据库不知道它们是否匹配,所以在进行匹配过滤或非匹配过滤时,不会返回这些结果。过滤数据时,一定要验证被过滤列中含NULL的行确实出现在返回的数据中。

分组查询

使用分组可以将数据分为多个逻辑组,对每个组进行聚集计算。

GROUP BY 关键字可以将查询结果按某个字段或多个字段进行分组。字段中值相等的为一组。
SELECT vend_id,COUNT(*) AS num
FROM products
GROUP BY vend_id;
上面的SELECT语句指定了两个列:
vend_id包含产品供应商的ID, num_prods为计算字段(用COUNT(*)函数建立)。
GROUP BY子句指示DBMS按vend_id排序并分组数据。这就会对每个vend_id而不是整个表计算num_prods一次。
从输出中可以看到,供应商BRS01有3个产品,供应商DLL01有4个产品,而供应商FNG01有2个产品。
因为使用了GROUP BY,就不必指定要计算和估值的每个组了。系统会自动完成。GROUPBY子句指示DBMS分组数据,然后对每个组而不是整个结果集进行聚集。


GROUP BY 属性名 [HAVING 条件表达式][WITH ROLLUP]

“属性名”是指按照该字段的值进行分组;“HAVING条件表达式”用来限制分组后的显示;
WITH ROLLUP关键字将会在所有记录的最后加上一条记录。该记录是上面所有记录的总和。(int类型则值相加、字符类型则一一列举出来)

1、单独使用GROUP BY关键字,查询的结果就是字段取值的分组情况。但每组只显示该组的第一条记录。

2、GROUP BY关键字可以和GROUP_CONCAT()函数一起使用时,GROUP_CONCAT()函数会把每个分组中指定字段值都显示出来。

3、GROUP BY关键字与集合函数一起使用时(集合函数包括COUNT()、SUM()、AVG()、MAX()、MIN());通常先使用GROUP BY关键字将记录分组,然后每组都使用集合函数进行计算。在统计时经常需要使用GROUP BY关键字和集合函数。

4、GROUP BY关键字与HAVING 一起使用,“HAVING条件表达式”可以限制输出的结果。

说明:“HAVING条件表达式”与“WHERE条件表达式”都是用来限制显示的。但是,两者起作用的地方不一样。“WHERE条件表达式”作用于表或者视图,是表和视图的查询条件。“HAVING条件表达式”作用于分组后的记录,用于选择满足条件的组。

5、按多字段进行分组
GROUP BY 属性名1,属性名2

分组过程中,先按照属性1进行分组,遇到属性1的值相等的情况时,再把属性1值相等的记录按属性2进行分组;
在使用GROUP BY子句前,需要知道一些重要的规定。
  1.  GROUP BY子句可以包含任意数目的列,因而可以对分组进行嵌套,更细致地进行数据分组。
  2.  如果在GROUP BY子句中嵌套了分组,数据将在最后指定的分组上进行汇总。换句话说,在建立分组时,指定的所有列都一起计算(所以不能从个别的列取回数据)。
  3.  GROUP BY子句中列出的每一列都必须是检索列或有效的表达式(但不能是聚集函数)。如果在SELECT中使用表达式,则必须在GROUP BY子句中指定相同的表达式。不能使用别名。
  4.  大多数SQL实现不允许GROUP BY列带有长度可变的数据类型(如文本或备注型字段)。
  5.  除聚集计算语句外,SELECT语句中的每一列都必须在GROUP BY子句中给出。
  6.  如果分组列中包含具有NULL值的行,则NULL将作为一个分组返回。如果列中有多行NULL值,它们将分为一组。
  7.  GROUP BY子句必须出现在WHERE子句之后,ORDER BY子句之前。
提示
HAVING支持所有WHERE操作符在第4课和第5课中,我们学习了WHERE子句的条件(包括通配符条件和带多个操作符的子句)。学过的这些有关WHERE的所有技术和选项都适用于HAVING。它们的句法是相同的,只是关键字有差别。
说明:HAVING和WHERE的差别
这里有另一种理解方法,WHERE在数据分组前进行过滤,HAVING在数据分组后进行过滤。这是一个重要的区别,WHERE排除的行不包括在分组中。这可能会改变计算值,从而影响HAVING子句中基于这些值过滤掉的分组。
说明:使用HAVING和WHERE
HAVING与WHERE非常类似,如果不指定GROUP BY,则大多数DBMS会同等对待它们。不过,你自己要能区分这一点。使用HAVING时应该结合GROUP BY子句,而WHERE子句用于标准的行级过滤。

分组和排序

GROUP BY和ORDER BY经常完成相同的工作,但它们非常不同,理解这一点很重要。表10-1汇总了它们之间的差别。

表10-1中列出的第一项差别极为重要。
我们经常发现,用GROUP BY分组的数据确实是以分组顺序输出的。但并不总是这样,这不是SQL规范所要求的。此外,即使特定的DBMS总是按给出的GROUP BY子句排序数据,用户也可能会要求以不同的顺序排序。就因为你以某种方式分组数据(获得特定的分组聚集值),并不表示你需要以相同的方式排序输出。应该提供明确的ORDER BY子句,即使其效果等同于GROUP BY子句。
提示:
不要忘记ORDER BY一般在使用GROUP BY子句时,应该也给出ORDER BY子句。这是保证数据正确排序的唯一方法。千万不要仅依赖GROUP BY排序数据。

用LIMIT限制查询结果的数量

LIMIT关键字有两种使用方式:不指定初始位置、指定初始位置

1、不指定初始位置
SELECT prod_name
FROM products
LIMIT 5

LIMIT 记录数 //仅显示“记录数”的条数

2、指定初始位置
SELECT prod_name
FROM products
LIMIT 2,2

LIMIT关键字可以指定从哪条记录开始显示,并且可以指定显示多少条记录。

LIMIT 初始位置,记录数 //“初始位置”参数指定从哪条记录开始显示;“记录数”参数辨识显示的条数 注:位置从零开始计数

使用集合函数查询(放置在SELECT后、FROM前)

聚集函数(aggregate function)
对某些行运行的函数,计算并返回一个值。
集合函数包括COUNT()、SUM()、AVG()、MAX()、MIN();

COUNT()函数用来统计记录的条数。(也可按照属性名分别计算记录的总数)

COUNT()函数有两种使用方式:

  1. 使用COUNT(*)对表中行的数目进行计数,不管表列中包含的是空值(NULL)还是非空值。
  2. 使用COUNT(列或行)对特定列中具有值的行进行计数,忽略NULL值。
说明:NULL值如果指定列名,则COUNT()函数会忽略指定列的值为空的行,但如果COUNT()函数中用的是星号(*),则不忽略。
SUM()函数可以求出表中某个字段取值的总和。 (SUM()函数只能计算数值类型的字段,包括INT()类型、FLOAT()类型、DOUBLE()类型、DECIMAL()类型。不能计算字符类型,计算结果都为0)
提示:在多个列上进行计算如本例所示,利用标准的算术操作符,所有聚集函数都可用来执行多个列上的计算。
MAX()函数可以求出表中某个字段取值的最大值。(MAX()函数是使用字符对应的ASCII码进行计算的)
注:需指定列名

提示:对非数值数据使用MAX()虽然MAX()一般用来找出最大的数值或日期值,但许多(并非所有)DBMS允许将它用来返回任意列中的最大值,包括返回文本列中的最大值。

在用于文本数据时,MAX()返回按该列排序后的最后一行。
说明:NULL值MAX()函数忽略列值为NULL的行。
MIN()函数可以求出表中某个字段取值的最小值。
提示:对非数值数据使用MIN()虽然MIN()一般用来找出最小的数值或日期值,但许多(并非所有)DBMS允许将它用来返回任意列中的最小值,包括返回文本列中的最小值。在用于文本数据时,MIN()返回该列排序后最前面的行。
说明:NULL值MAX()函数忽略列值为NULL的行。
AVG()函数可以求出表中某个字段取值的平均值。(ZVG()函数经常与GROUP BY字段一起使用,用来计算每个分组的平均值)
注意:只用于单个列AVG()只能用来确定特定数值列的平均值,而且列名必须作为函数参数给出。为了获得多个列的平均值,必须使用多个AVG()函数。
说明:NULL值AVG()函数忽略列值为NULL的行。

以上5个聚集函数都可以如下使用。
  1. 对所有行执行计算,指定ALL参数或不指定参数(因为ALL是默认行为)。
  2. 只包含不同的值,指定DISTINCT参数。

目前为止的所有聚集函数例子都只涉及单个函数。但实际上,SELECT语句可根据需要包含多个聚集函数。请看下面的例子:

这里用单条SELECT语句执行了4个聚集计算,返回4个值(Products表中物品的数目,产品价格的最高值、最低值以及平均值)。
注意:取别名
在指定别名以包含某个聚集函数的结果时,不应该使用表中实际的列名。虽然这样做也算合法,但许多SQL实现不支持,可能会产生模糊的错误消息。

select子句顺序

下面回顾一下SELECT语句中子句的顺序。表10-2以在SELECT语句中使用时必须遵循的次序,列出迄今为止所学过的子句。

子查询

可以把一条SELECT语句返回的结果用于另一条SELECT语句的WHERE子句。

子查询中的WHERE子句与前面使用的WHERE子句稍有不同,因为它使用了完全限定列名,而不只是列名,它指定表名和列名。

注意:完全限定列名
你已经看到了为什么要使用完全限定列名,没有具体指定就会返回错误结果,因为DBMS会误解你的意思。有时候,由于出现冲突列名而导致的歧义性,会引起DBMS抛出错误信息。例如,WHERE或ORDER BY子句指定的某个列名可能会出现在多个表中。好的做法是,如果在SELECT语句中操作多个表,就应使用完全限定列名来避免歧义。
完全限定类名包含表名和列名,这样的话不会出现无法明确指定。

提示:格式化SQL
包含子查询的SELECT语句难以阅读和调试,它们在较为复杂时更是如此。如上所示,把子查询分解为多行并进行适当的缩进,能极大地简化子查询的使用。顺便一提,这就是颜色编码起作用的地方,好的DBMS客户端正是出于这个原因使用了颜色代码SQL
注意:
子查询和性能这里给出的代码有效,并且获得了所需的结果。但是,使用子查询并不总是执行这类数据检索的最有效方法

提示:
不止一种解决方案正如这一课前面所述,虽然这里给出的样例代码运行良好,但它并不是解决这种数据检索的最有效方法。
特别注意:
注意:
只能是单列作为子查询的SELECT语句只能查询单个列。企图检索多个列将返回错误。

联结表

关键是,相同的数据出现多次决不是一件好事,这是关系数据库设计的基础。关系表的设计就是要把信息分解成多个表,一类数据一个表。各表通过某些共同的值互相关联(所以才叫关系数据库)。
由于数据不重复,数据显然是一致的,使得处理数据和生成报表更简单。总之,关系数据可以有效地存储,方便地处理。因此,关系数据库的可伸缩性远比非关系数据库要好。

可伸缩(scale)
能够适应不断增加的工作量而不失败。设计良好的数据库或应用程序称为可伸缩性好(scalewell)。
将数据分解为多个表能更有效地存储,更方便地处理,并且可伸缩性更好。
但这些好处是有代价的。如果数据存储在多个表中,怎样用一条SELECT语句就检索出数据呢?
答案是使用联结
简单说,联结是一种机制,用来在一条SELECT语句中关联表,因此称为联结。使用特殊的语法,可以联结多个表返回一组输出,联结在运行时关联表中正确的行。
创建联结非常简单,指定要联结的所有表以及关联它们的方式即可。
警告
完全限定列名就像前一课提到的,在引用的列可能出现歧义时,必须使用完全限定列名(用一个句点分隔表名和列名)。如果引用一个没有用表名限制的具有歧义的列名,大多数DBMS会返回错误。

笛卡儿积(cartesian product)
由没有联结条件的表关系返回的结果为笛卡儿积。检索出的行的数目将是第一个表中的行数乘以第二个表中的行数。

提示:叉联结
有时,返回笛卡儿积的联结,也称叉联结(cross join)
注意:
不要忘了WHERE子句要保证所有联结都有WHERE子句,否则DBMS将返回比想要的数据多得多的数据。同理,要保证WHERE子句的正确性。不正确的过滤条件会导致DBMS返回不正确的数据。
内联结

目前为止使用的联结称为等值联结(equijoin),它基于两个表之间的相等测试。这种联结也称为内联结(inner join)。
简单格式
SELECT vend_name,prod_name,prod_price
FROM vendors,products
WHERE vendors.vend_id = products.vend_id
标准格式
SELECT vend_name,prod_name,prod_price
FROM vendors INNER JOIN products
NO vendors.vend_id = products.vend_id

说明:“正确的”语法
ANSI SQL规范首选INNER JOIN语法,之前使用的是简单的等值语法。其实,SQL语言纯正论者是用鄙视的眼光看待简单语法的。这就是说,DBMS的确支持简单格式和标准格式,我建议你要理解这两种格式,具体使用就看你用哪个更顺手了。

多表联结

SQL不限制一条SELECT语句中可以联结的表的数目。创建联结的基本规则也相同。首先列出所有表,然后定义表之间的关系
注意:
性能考虑DBMS在运行时关联指定的每个表,以处理联结。这种处理可能非常耗费资源,因此应该注意,不要联结不必要的表。联结的表越多,性能下降越厉害。
注意:
联结中表的最大数目虽然SQL本身不限制每个联结约束中表的数目,但实际上许多DBMS都有限制。请参阅具体的DBMS文档以了解其限制。

提示:多做实验
可以看到,执行任一给定的SQL操作一般不止一种方法。很少有绝对正确或绝对错误的方法。性能可能会受操作类型、所使用的DBMS、表中数据量、是否存在索引或键等条件的影响。因此,有必要试验不同的选择机制,找出最适合具体情况的方法。
联结是SQL中一个最重要、最强大的特性,有效地使用联结需要对关系数据库设计有基本的了解。

创建高级联结

使用表别名

SQL除了可以对列名和计算字段使用别名,还允许给表名起别名。这样做有两个主要理由:
  1. 缩短SQL语句;
  2. 允许在一条SELECT语句中多次使用相同的表。

可以看到,FROM子句中的三个表全都有别名。Customers AS C使用C作为Customers的别名,如此等等。
这样,就可以使用省略的C而不用全名Customers。
在这个例子中,表别名只用于WHERE子句。其实它不仅能用于WHERE子句,还可以用于SELECT的列表、ORDER BY子句以及其他语句部分。

注意:Oracle中没有ASOracle不支持AS关键字。要在Oracle中使用别名,可以不用AS,简单地指定列名即可(因此,应该是Customers C,而不是CustomersAS C)。
需要注意,表别名只在查询执行中使用。与列别名不一样,表别名不返回到客户端。


迄今为止,我们使用的只是内联结或等值联结的简单联结。现在来看三种其他联结:自联结(self-join)、自然联结(natural join)和外联结(outer join)。

自联结

如前所述,使用表别名的一个主要原因是能在一条SELECT语句中不止一次引用相同的表。
下面举一个例子。
假如要给与Jim Jones同一公司的所有顾客发送一封信件。这个查询要求首先找出Jim Jones工作的公司,然后找出在该公司工作的顾客。
下面是解决此问题的一种方法:

子查询

这是第一种解决方案,使用了子查询。
内部的SELECT语句做了一个简单检索,返回Jim Jones工作公司的cust_name。该名字用于外部查询的WHERE子句中,以检索出为该公司工作的所有雇员

自联结:

此查询中需要的两个表实际上是相同的表,因此Customers表在FROM子句中出现了两次。虽然这是完全合法的,但对Customers的引用具有歧义性,因为DBMS不知道你引用的是哪个Customers表。解决此问题,需要使用表别名。Customers第一次出现用了别名c1,第二次出现用了别名c2。现在可以将这些别名用作表名。例如,SELECT语句使用c1前缀明确给出所需列的全名。如果不这样,DBMS将返回错误,因为名为cust_id、cust_name、cust_contact的列各有两个。DBMS不知道想要的是哪一列(即使它们其实是同一列)。WHERE首先联结两个表,然后按第二个表中的cust_contact过滤数据,返回所需的数据。

提示:
用自联结而不用子查询自联结通常作为外部语句,用来替代从相同表中检索数据的使用子查询语句。
虽然最终的结果是相同的,但许多DBMS处理联结远比处理子查询快得多。
应该试一下两种方法,以确定哪一种的性能更好。

自然联结

无论何时对表进行联结,应该至少有一列不止出现在一个表中(被联结的列)。
标准的联结(前一课中介绍的内联结)返回所有数据,相同的列甚至多次出现。自然联结排除多次出现,使每一列只返回一次。
怎样完成这项工作呢?
答案是,系统不完成这项工作,由你自己完成它。自然联结要求你只能选择那些唯一的列,一般通过对一个表使用通配符(SELECT *),而对其他表的列使用明确的子集来完成。下面举一个例子:

在这个例子中,通配符只对第一个表使用。所有其他列明确列出,所以没有重复的列被检索出来。
事实上,我们迄今为止建立的每个内联结都是自然联结,很可能永远都不会用到不是自然联结的内联结。

外联结

许多联结将一个表中的行与另一个表中的行相关联,但有时候需要包含没有关联行的那些行。例如,可能需要使用联结完成以下工作:
  1. 对每个顾客下的订单进行计数,包括那些至今尚未下订单的顾客;
  2. 列出所有产品以及订购数量,包括没有人订购的产品;
  3. 计算平均销售规模,包括那些至今尚未下订单的顾客。
在上述例子中,联结包含了那些在相关表中没有关联行的行。这种联结称为外联结。

注意:
语法差别需要注意,用来创建外联结的语法在不同的SQL实现中可能稍有不同。

下面段落中描述的各种语法形式覆盖了大多数实现,在继续学习之前请参阅你使用的DBMS文档,以确定其语法。
提示:

外联结的类型要记住,总是有两种基本的外联结形式左外联结和右外联结。
它们之间的唯一差别是所关联的表的顺序。
换句话说,调整FROM或WHERE子句中表的顺序,左外联结可以转换为右外联结。因此,这两种外联结可以互换使用,哪个方便就用哪个。

还存在另一种外联结,就是全外联结(full outer join),它检索两个表中的所有行并关联那些可以关联的行。与左外联结或右外联结包含一个表的不关联的行不同,全外联结包含两个表的不关联的行。全外联结的语法如下:
注意:
FULL OUTER JOIN的支持Access、MariaDB、MySQL、Open Office Base和SQLite不支持FULL OUTER JOIN语法。

聚集函数可与联结一起使用

聚集函数用来汇总数据。
虽然至今为止我们举的聚集函数的例子都只是从一个表中汇总数据,但这些函数也可以与联结一起使用。

使用联结和联结条件


总结讨论联结的这两课前,有必要汇总一下联结及其使用的要点
  1. 注意所使用的联结类型。一般我们使用内联结,但使用外联结也有效。
  2. 关于确切的联结语法,应该查看具体的文档,看相应的DBMS支持何种语法(大多数DBMS使用这两课中描述的某种语法)。
  3. 保证使用正确的联结条件(不管采用哪种语法),否则会返回不正确的数据。
  4. 应该总是提供联结条件,否则会得出笛卡儿积。
  5. 在一个联结中可以包含多个表,甚至可以对每个联结采用不同的联结类型。虽然这样做是合法的,一般也很有用,但应该在一起测试它们前分别测试每个联结。这会使故障排除更为简单。

组合查询

多数SQL查询只包含从一个或多个表中返回数据的单条SELECT语句。
但是,SQL也允许执行多个查询(多条SELECT语句),并将结果作为一个查询结果集返回。这些组合查询通常称为并(union)或复合查询(compound query)

主要有两种情况需要使用组合查询:
  1. 在一个查询中从不同的表返回结构数据;
  2. 对一个表执行多个查询,按一个查询返回数据。
提示:
组合查询和多个WHERE条件多数情况下,组合相同表的两个查询所完成的工作与具有多个WHERE子句条件的一个查询所完成的工作相同。换句话说,任何具有多个WHERE子句的SELECT语句都可以作为一个组合查询,在下面可以看到这一点。

创建组合查询

可用UNION操作符来组合数条SQL查询。利用UNION,可给出多条SELECT语句,将它们的结果组合成一个结果集。

使用UNION很简单,所要做的只是给出每条SELECT语句,在各条语句之间放上关键字UNION。

举个例子,假如需要Illinois、Indiana和Michigan等美国几个州的所有顾客的报表,还想包括不管位于哪个州的所有的Fun4All。当然可以利用WHERE子句来完成此工作,不过这次我们使用UNION。如上所述,创建UNION涉及编写多条SELECT语句。首先来看单条语句:

语句一:


结果:


语句二:


结果:


第一条SELECT把Illinois、Indiana、Michigan等州的缩写传递给IN子句,检索出这些州的所有行。
第二条SELECT利用简单的相等测试找出所有Fun4All。
组合这两条语句,可以如下进行:

结果:

这条语句由前面的两条SELECT语句组成,之间用UNION关键字分隔。
UNION指示DBMS执行这两条SELECT语句,并把输出组合成一个查询结果集。
为了便于参考,这里给出使用多条WHERE子句而不是UNION的相同查询:

适用范围:
在这个简单的例子中,使用UNION可能比使用WHERE子句更为复杂。
但对于较复杂的过滤条件,或者从多个表(而不是一个表)中检索数据的情形,使用UNION可能会使处理更简单。

提示:
UNION的限制使用UNION组合SELECT语句的数目,SQL没有标准限制。
但是,最好是参考一下具体的DBMS文档,了解它是否对UNION能组合的最大语句数目有限制。
注意:
性能问题多数好的DBMS使用内部查询优化程序,在处理各条SELECT语句前组合它们。理论上讲,这意味着从性能上看使用多条WHERE子句条件还是UNION应该没有实际的差别。
不过我说的是理论上,实践中多数查询优化程序并不能达到理想状态,所以最好测试一下这两种方法,看哪种工作得更好。

UNION规则

可以看到,UNION非常容易使用,但在进行组合时需要注意几条规则。
  1. UNION必须由两条或两条以上的SELECT语句组成,语句之间用关键字UNION分隔(因此,如果组合四条SELECT语句,将要使用三个UNION关键字)。
  2. UNION中的每个查询必须包含相同的列、表达式或聚集函数(不过,各个列不需要以相同的次序列出)。
  3. 列数据类型必须兼容:类型不必完全相同,但必须是DBMS可以隐含转换的类型(例如,不同的数值类型或不同的日期类型)。
如果遵守了这些基本规则或限制,则可以将UNION用于任何数据检索操作。

UNION从查询结果集中自动去除了重复的行

换句话说,它的行为与一条SELECT语句中使用多个WHERE子句条件一样。因为Indiana州有一个Fun4All单位,所以两条SELECT语句都返回该行。使用UNION时,重复的行会被自动取消。这是UNION的默认行为,如果愿意也可以改变它。事实上,如果想返回所有的匹配行,可使用UNION ALL而不是UNION。

提示:
UNION与WHERE这一课一开始我们说过,UNION几乎总是完成与多个WHERE条件相同的工作。UNION ALL为UNION的一种形式,它完成WHERE子句完成不了的工作。如果确实需要每个条件的匹配行全部出现(包括重复行),就必须使用UNION ALL,而不是WHERE。

SELECT语句的输出用ORDER BY子句排序。在用UNION组合查询时,只能使用一条ORDER BY子句,它必须位于最后一条SELECT语句之后。
对于结果集,不存在用一种方式排序一部分,而又用另一种方式排序另一部分的情况,因此不允许使用多条ORDER BY子句

下面的例子对前面UNION返回的结果进行排序:


这条UNION在最后一条SELECT语句后使用了ORDER BY子句
虽然ORDER BY子句似乎只是最后一条SELECT语句的组成部分,但实际上DBMS将用它来排序所有SELECT语句返回的所有结果

说明:
其他类型的UNION某些DBMS还支持另外两种UNION:EXCEPT(有时称为MINUS)可用来检索只在第一个表中存在而在第二个表中不存在的行;而INTERSECT可用来检索两个表中都存在的行。实际上,这些UNION很少使用,因为相同的结果可利用联结得到。
提示:
操作多个表为了简单,本课中的例子都是使用UNION来组合针对同一表的多个查询。
实际上,UNION在需要组合多个表的数据时也很有用,即使是有不匹配列名的表,在这种情况下,可以将UNION与别名组合,检索一个结果集。
小结:
利用UNION,可以把多条查询的结果作为一条组合查询返回,不管结果中有无重复。使用UNION可极大地简化复杂的WHERE子句,简化从多个表中检索数据的工作。

插入数据

顾名思义,INSERT用来将行插入(或添加)到数据库表。

插入有几种方式:
  1. 插入完整的行;
  2. 插入行的一部分;
  3. 插入某些查询的结果。
权限
提示:
插入及系统安全使用INSERT语句可能需要客户端/服务器DBMS中的特定安全权限。在你试图使用INSERT前,应该保证自己有足够的安全权限。
命令:
insert into <表名> [( <字段名 1>[,..<字段名 n > ])] values ( 值 1 )[, ( 值 n )]
存储到表中每一列的数据在VALUES子句中给出,必须给每一列提供一个值。如果某列没有值,如上面的cust_contact和cust_email列,则应该使用NULL值(假定表允许对该列指定空值)。各列必须以它们在表定义中出现的次序填充。
INTO关键字
提示:
INTO关键字在某些SQL实现中,跟在INSERT之后的INTO关键字是可选的。
但是,即使不一定需要,最好还是提供这个关键字,这样做将保证SQL代码在DBMS之间可移植。
虽然这种语法很简单,但并不安全,应该尽量避免使用。
上面的SQL语句高度依赖于表中列的定义次序,还依赖于其容易获得的次序信息。即使可以得到这种次序信息,也不能保证各列在下一次表结构变动后保持完全相同的次序。
因此,编写依赖于特定列次序的SQL语句是很不安全的,这样做迟早会出问题。

编写INSERT语句的更安全(不过更烦琐)的方法如下:


这个例子与前一个INSERT语句的工作完全相同,但在表名后的括号里明确给出了列名。
在插入行时,DBMS将用VALUES列表中的相应值填入列表中的对应项。VALUES中的第一个值对应于第一个指定列名,第二个值对应于第二个列名,如此等等。
因为提供了列名,VALUES必须以其指定的次序匹配指定的列名不一定按各列出现在表中的实际次序
其优点是,即使表的结构改变,这条INSERT语句仍然能正确工作。
提示:总是使用列的列表不要使用没有明确给出列的INSERT语句。给出列能使SQL代码继续发挥作用,即使表结构发生了变化。
注意:小心使用VALUES
不管使用哪种INSERT语法,VALUES的数目都必须正确。如果不提供列名,则必须给每个表列提供一个值;如果提供列名,则必须给列出的每个列一个值。否则,就会产生一条错误消息,相应的行不能成功插入。
使用第二种方法可以省略某些列
注意:省略列

如果表的定义允许,则可以在INSERT操作中省略某些列。省略的列必须满足以下某个条件。
  1. 该列定义为允许NULL值(无值或空值)。
  2. 在表定义中给出默认值。这表示如果不给出值,将使用默认值。
注意:省略所需的值如果表中不允许有NULL值或者默认值,这时却省略了表中的值,DBMS就会产生错误消息,相应的行不能成功插入。

插入检索出的数据

INSERT一般用来给表插入具有指定列值的行。
INSERT还存在另一种形式,可以利用它将SELECT语句的结果插入表中,这就是所谓的INSERTSELECT。顾名思义,它是由一条INSERT语句和一条SELECT语句组成的


说明:新例子的说明
这个例子从一个名为CustNew的表中读出数据并插入到Customers表。
为了试验这个例子,应该首先创建和填充CustNew表。CustNew表的结构与附录A中描述的Customers表相同。
在填充CustNew时,不应该使用已经在Customers中用过的cust_id值(如果主键值重复,后续的INSERT操作将会失败)。
补充
这个例子使用INSERT SELECT从CustNew中将所有数据导入Customers。SELECT语句从CustNew检索出要插入的值,而不是列出它们。SELECT中列出的每一列对应于Customers表名后所跟的每一列。这条语句将插入多少行呢?这依赖于CustNew表有多少行。如果这个表为空,则没有行被插入(也不产生错误,因为操作仍然是合法的)。如果这个表确实有数据,则所有数据将被插入到Customers。
提示:INSERT SELECT中的列名
为简单起见,这个例子在INSERT和SELECT语句中使用了相同的列名。但是,不一定要求列名匹配。事实上,DBMS一点儿也不关心SELECT返回的列名。它使用的是列的位置,因此SELECT中的第一列(不管其列名)将用来填充表列中指定的第一列,第二列将用来填充表列中指定的第二列,如此等等。
INSERT SELECT中SELECT语句可以包含WHERE子句,以过滤插入的数据。
提示:
插入多行INSERT通常只插入一行。要插入多行,必须执行多个INSERT语句。INSERT SELECT是个例外,它可以用一条INSERT插入多行,不管SELECT语句返回多少行,都将被INSERT插入。

从一个表复制到另一个表

有一种数据插入不使用INSERT语句。要将一个表的内容复制到一个全新的表(运行中创建的表),可以使用SELECT INTO语句。
说明:DB2不支持DB2不支持这里描述的SELECT INTO。
与INSERT SELECT将数据添加到一个已经存在的表不同,SELECT INTO将数据复制到一个新表(有的DBMS可以覆盖已经存在的表,这依赖于所使用的具体DBMS)。
说明:INSERT SELECT与SELECT INTO它们之间的一个重要差别是前者插入数据,而后者导出数据。

这条SELECT语句创建一个名为CustCopy的新表,并把Customers表的整个内容复制到新表中。因为这里使用的是SELECT *,所以将在CustCopy表中创建(并填充)与Customers表的每一列相同的列。要想只复制部分的列,可以明确给出列名,而不是使用*通配符。

MariaDB、MySQL、Oracle、PostgreSQL和SQLite使用的语法稍有不同。

(待试验)

在使用SELECT INTO时,需要知道一些事情:
  1. 任何SELECT选项和子句都可以使用,包括WHERE和GROUP BY;
  2. 可利用联结从多个表插入数据;
  3. 不管从多少个表中检索数据,数据都只能插入到一个表中。
提示:进行表的复制
SELECT INTO是试验新SQL语句前进行表复制的很好工具。先进行复制,可在复制的数据上测试SQL代码,而不会影响实际的数据。

更新、修改数据

更新(修改)表中的数据,可以使用UPDATE语句。有两种使用UPDATE的方式:
  1. 更新表中的特定行;
  2. 更新表中的所有行。
注意:
不要省略WHERE子句在使用UPDATE时一定要细心。因为稍不注意,就会更新表中的所有行。使用这条语句前,请完整地阅读本节。
提示:
UPDATE与安全在客户端/服务器的DBMS中,使用UPDATE语句可能需要特殊的安全权限。在你使用UPDATE前,应该保证自己有足够的安全权限。
命令:update 表名 set 字段名 = 新内容
使用UPDATE语句非常容易,甚至可以说太容易了。
基本的UPDATE语句由三部分组成,分别是:
  1. 要更新的表;
  2. 列名和它们的新值;
  3. 确定要更新哪些行的过滤条件。
update 表名 
set 列名=  '新内容'
(   where语句  ) 

UPDATE语句总是以要更新的表名开始。
SET命令用来将新值赋给被更新的列。
UPDATE语句以WHERE子句结束,它告诉DBMS更新哪一行。没有WHERE子句,将会更新表中的所有行,这不是我们希望的。

在更新多个列时,只需要使用一条SET命令,每个“列=值”对之间用逗号分隔(最后一列之后不用逗号)。

提示:
在UPDATE语句中使用子查询UPDATE语句中可以使用子查询,使得能用SELECT语句检索出的数据更新列数据。
提示:
FROM关键字有的SQL实现支持在UPDATE语句中使用FROM子句,用一个表的数据更新另一个表的行。如想知道你的DBMS是否支持这个特性,请参阅它的文档。
要删除某个列的值,可设置它为NULL(假如表定义允许NULL值)
这与保存空字符串很不同(空字符串用’’表示,是一个值),而NULL表示没有值

删除数据

提示:
友好的外键第12课介绍了联结,简单联结两个表只需要这两个表中的公用字段。也可以让DBMS通过使用外键来严格实施关系(这些定义在附录A中)。存在外键时,DBMS使用它们实施引用完整性。例如要向Products表中插入一个新产品,DBMS不允许通过未知的供应商id插入它,因为vend_id列是作为外键连接到Vendors表的。那么,这与DELETE有什么关系呢?使用外键确保引用完整性的一个好处是,DBMS通常可以防止删除某个关系需要用到的行。例如,要从Products表中删除一个产品,而这个产品用在OrderItems的已有订单中,那么DELETE语句将抛出错误并中止。这是总要定义外键的另一个理由。
提示:
FROM关键字在某些SQL实现中,跟在DELETE后的关键字FROM是可选的。但是即使不需要,也最好提供这个关键字。这样做将保证SQL代码在DBMS之间可移植。
DELETE不需要列名或通配符。DELETE删除整行而不是删除列。要删除指定的列,请使用UPDATE语句
提示:更快的删除
如果想从表中删除所有行,不要使用DELETE。可使用TRUNCATETABLE语句,它完成相同的工作,而速度更快(因为不记录数据的变动)。
说明:
删除表的内容而不是表DELETE语句从表中删除行,甚至是删除表中所有行。但是,DELETE不删除表本身。\

下面是许多SQL程序员使用UPDATE或DELETE时所遵循的重要原则
  1. 除非确实打算更新和删除每一行,否则绝对不要使用不带WHERE子句的UPDATE或DELETE语句。
  2. 保证每个表都有主键(如果忘记这个内容,请参阅第12课),尽可能像WHERE子句那样使用它(可以指定各主键、多个值或值的范围)。
  3. 在UPDATE或DELETE语句使用WHERE子句前,应该先用SELECT进行测试,保证它过滤的是正确的记录,以防编写的WHERE子句不正确。
  4. 使用强制实施引用完整性的数据库(关于这个内容,请参阅第12课),这样DBMS将不允许删除其数据与其他表相关联的行。
  5. 有的DBMS允许数据库管理员施加约束,防止执行不带WHERE子句的UPDATE或DELETE语句。如果所采用的DBMS支持这个特性,应该使用它。若是SQL没有撤销(undo)按钮,应该非常小心地使用UPDATE和DELETE,否则你会发现自己更新或删除了错误的数据。

注释

注释使用--(两个连字符)嵌在行内。-- 之后的文本就是注释
SELECT prod_name -- 注释
FROM products
LIMIT 2,2
注意:要在“--”后加一个空格,才会有效果
在一行的开始处使用#,这一整行都将作为注释。
SELECT prod_name # 注释
FROM products
LIMIT 2,2
注释从/*开始,到*/结束,/*和*/之间的任何内容都是注释。这种方式常用于给代码加注释,
SELECT prod_name /* 注释*/
FROM products
LIMIT 2,2

视图

视图是虚拟的表。与包含数据的表不一样,视图只包含使用时动态检索数据的查询。

为什么使用视图

  • 重用SQL语句。
  • 简化复杂的SQL操作。在编写查询后,可以方便地重用它而不必知道其基本查询细节。
  • 使用表的一部分而不是整个表。
  • 保护数据。可以授予用户访问表的特定部分的权限,而不是整个表的访问权限。
  • 更改数据格式和表示。视图可返回与底层表的表示和格式不同的数据。
创建视图之后,可以用与表基本相同的方式使用它们。

注意:
性能问题因为视图不包含数据,所以每次使用视图时,都必须处理查询执行时需要的所有检索。如果你用多个联结和过滤创建了复杂的视图或者嵌套了视图,性能可能会下降得很厉害。
因此,在部署使用了大量视图的应用前,应该进行测试。

创建视图

视图用CREATE VIEW语句来创建
说明:视图重命名删除视图,可以使用DROP语句,其语法为
DROP VIEW viewname;
覆盖(或更新)视图,必须先删除它,然后再重新创建。

利用视图简化复杂的联结


这条语句创建一个名为ProductCustomers的视图,它联结三个表,返回已订购了任意产品的所有顾客的列表。
如果执行SELECT * FROMProductCustomers,将列出订购了任意产品的顾客。


这条语句通过WHERE子句从视图中检索特定数据。
当DBMS处理此查询时,它将指定的WHERE子句添加到视图查询中已有的WHERE子句中,以便正确过滤数据。
可以看出,视图极大地简化了复杂SQL语句的使用。利用视图,可一次性编写基础的SQL,然后根据需要多次使用。

在需要进行复杂数据的查询时,可使用视图来进行简化 。
视图非常容易创建,而且很好使用。正确使用,视图可极大地简化复杂数据的处理。

注意:
视图的规则较多,在创建视图前,有必要花点时间了解必须遵守的规定。

小结

视图为虚拟的表。它们包含的不是数据而是根据需要检索数据的查询。视图提供了一种封装SELECT语句的层次,可用来简化数据处理,重新格式化或保护基础数据。

未完待续