文章目录
第一章 SQL与MySQL1 数据库基础2 什么是SQL3 客户机—服务器软件4 MySQL工具mysql命令行实用程序(使用最多的实用程序之一)MySQL AdministratorMySQL Query Browser第二章 使用MySQL1 连接2选择数据库3了解数据库和表4 注释第三章 检索数据1 SELECT语句【附录】SELECT子句顺序(从前到后)2 检索列检索单个列检索多个列检索所有列检索不同的行3 限制结果(LIMIT子句)4 使用完全限定的表名5 排序检索数据按多个列排序指定排序方向(找最值)第四章 过滤数据1 使用WHERE子句2 WHERE子句操作符检查单个值不匹配检查范围值检查空值检查3 组合WHERE子句AND操作符OR操作符()操作符--计算次序IN操作符NOT操作符4 用通配符进行过滤LIKE操作符百分号(%)通配符下划线(_)通配符使用通配符的技巧5 用正则表达式进行搜索基本字符匹配(REGEXP关键字)正则表达式中的一个特殊符号(.)LIKE与REGEXP的区别进行OR匹配匹配几个字符之一(另一种形式的OR语句)匹配范围匹配特殊字符匹配字符类匹配多个实例定位符第五章 创建计算字段1 计算字段2 计算字段常用函数拼接字段删除数据两侧多余的空格使用别名3 执行算术计算第六章 使用数据处理函数1 函数2 使用函数文本处理函数常用的日期和时间处理函数数值处理函数第七章 汇总数据1 聚集函数(也是返回计算字段,建议别名化)2 聚集不同的值3 组合聚集函数第八章 分组数据1 数据分组2 创建分组3 过滤分组4 GROUP BY和ORDER BY的区别第九章 嵌套查询1 使用子查询利用子查询进行过滤作为计算字段使用子查询2 联结表联结创建联结使用联结和联结条件3 内部联结(相比WHERE首选INNER JOIN语法)联结多个表使用表别名4 使用不同类型的联结自联结自然联结外部联结(关键字OUTER JOIN)5 使用带聚集函数的联结第十章 组合查询1 创建查询使用UNIONUNION规则2 包含或取消重复的行3 对组合查询结果排序第十一章 全文本搜索1 使用全文本搜索启用全文本搜索支持进行全文本搜索支持(搜索不区分大小写)2使用查询扩展3 布尔文本搜索(更细致地查找)4 全文本搜索的使用说明第一章 SQL与MySQL
1 数据库基础
数据库软件应称为DBMS(数据库管理系统)。而数据库是通过DBMS创建和操纵的容器。
【定义1】数据库(database) 保存有组织的数据的容器(通常是一个文件或一组文件)。
【定义2】表(table) 是某种特定类型数据的结构化清单。表名的唯一性取决于多个因素,如数据库名和表名等的结合。这表示,虽然在相同数据库中不能两次使用相同的表名,但在不同的数据库中却可以使用相同的表名。
【定义3】模式(schema) 关于数据库和表的布局及特性的信息。
【定义4】表由列组成。列中存储着表中某部分的信息。而列(column) 表中的一个字段。所有表都是由一个或多个列组成的。
【定义5】数据类型(datatype) 所容许的数据的类型。每个表列都有相应的数据类型,它限制(或容许)该列中存储的数据。
【定义6】行(row) 表中的一个记录。表中的数据是按行存储的,所保存的每个记录存储在自己的行内。
【定义7】主键(primary key)一列(或一组列),其值能够唯一区分表中每个行。唯一标识表中每行的这个列(或这组列)称为主键。主键用来表示一个特定的行。没有主键,更新或删除表中特定行很困难,因为没有安全的方法保证只涉及相关的行。
其主键规定有两条:
任意两行都不具有相同的主键值;每个行都必须具有一个主键值(主键列不允许NULL值)。
主键通常定义在表的一列上,但这并不是必需的,也可以一起使用多个列作为主键,规则做出相应改变即可(单列值可不唯一,但一组列值需要唯一)。
2 什么是SQL
SQL(发音为字母S-Q-L或sequel)是结构化查询语言(Structured QueryLanguage)的缩写。SQL是一种专门用来与数据库通信的语言。本书讲授的SQL是专门针对MySQL的,虽然书中所讲授的多数语法也适用于其他DBMS,但不要认为这些SQL语法是完全可移植的。
MySQL是一种DBMS,即它是一种数据库软件。
3 客户机—服务器软件
DBMS可分为两类:一类为基于共享文件系统的DBMS,另一类为基于客户机—服务器的DBMS。。前者(包括诸如Microsoft Access和FileMaker)用于桌面用途,通常不用于高端或更关键的应用。而MySQL、Oracle以及Microsoft SQL Server等数据库是基于客户机—服务器的数据库。
服务器部分是负责所有数据访问和处理的一个软件。这个软件运行在称为数据库服务器的计算机上。与数据文件打交道的只有服务器软件。服务器软件为MySQL DBMS。你可以在本地安装的副本上运行,也可以连接到运行在你具有访问权的远程服务器上的一个副本。客户机是与用户打交道的软件。客户机可以是MySQL提供的工具、脚本语言(如Perl)、Web应用开发语言(如ASP、ColdFusion、JSP和PHP)、程序设计语言(如C、C++、Java)等。
4 MySQL工具
mysql命令行实用程序(使用最多的实用程序之一)
每个MySQL安装都有一个名为mysql的简单命令行实用程序。这个实用程序没有下拉菜单、流行的用户界面、鼠标支持或任何类似的东西。其需要注意:
命令输入在mysql>之后;命令用;或\g结束,换句话说,仅按Enter不执行命令;输入help或\h获得帮助,也可以输入更多的文本获得特定命令的帮助(如,输入help select获得使用SELECT语句的帮助);输入quit或exit退出命令行实用程序。
MySQL Administrator
MySQL Administrator(MySQL管理器)是一个图形交互客户机,用来简化MySQL服务器的管理。
MySQL Query Browser
MySQL Query Browser为一个图形交互客户机,用来编写和执行MySQL命令。
第二章 使用MySQL
1 连接
MySQL与所有客户机—服务器DBMS一样,要求在能执行命令之前登录到DBMS。并且,MySQL在内部保存自己的用户列表,并且把每个用户与各种权限关联起来。
为了连接到MySQL,需要以下信息:
主机名(计算机名)——如果连接到本地MySQL服务器,为localhost端口(如果使用默认端口3306之外的端口);一个合法的用户名用户口令(如果需要)
格式为:mysql -h 主机IP -P 端口 -u 用户名 -p 密码
而对于服务器来说,想要修改MySQL开启服务的端口,仅需要:
打开mysql配置文件my.ini或f找到port=3306
把3306修改成你需要的端口,然后重启mysql就好了
2选择数据库
【定义】关键字(key word) 作为MySQL语言组成部分的一个保留字。决不要用关键字命名一个表或列。
【例子】为了使用crashcourse数据库,应该输入以下内容:
USE crashcourse
记住,必须先使用USE打开数据库,才能读取其中的数据。
3了解数据库和表
如果你不知道可以使用的数据库名时怎么办?可用MySQL的SHOW命令来显示这些信息。
SHOW DATABASES
返回可用数据库的一个列表
为了获得一个数据库内的表的列表,使用SHOW TABLES;
【案例】SHOW COLUMNS
要求给出一个表名(这个例子中的 FROM customers),它对每个字段返回一行,行中包含字段名、数据类型、是否允许NULL、键信息、默认值以及其他信息(如字段cust_id的auto_increment)
MySQL支持用DESCRIBE作为SHOW COLUMNS FROM的一种快捷方式。换句话说,
DESCRIBE customers
是SHOW COLUMNS FROM customers
的一种快捷方式。
所支持的其他SHOW语句还有:
SHOW STATUS
,用于显示广泛的服务器状态信息;SHOW CREATE DATABASE
和SHOW CREATE TABLE
,分别用来显示创建特定数据库或表的MySQL语句;SHOW GRANTS
,用来显示授予用户(所有用户或特定用户)的安全权限;SHOW ERRORS
和SHOW WARNINGS
,用来显示服务器错误或警告消息。
4 注释
前面放置--
--这是一段注释SELECT numFROM aa;
第三章 检索数据
1 SELECT语句
最经常使用的SQL语句就是SELECT语句了。它的用途是从一个或多个表中检索信息。为了使用SELECT检索表数据,必须至少给出两条信息——想选择什么,以及从什么地方选择。
【附录】SELECT子句顺序(从前到后)
2 检索列
检索单个列
SELECT prod_name FROM products;
上述语句利用SELECT语句从products表中检索一个名为prod_name的列。所需的列名在SELECT关键字之后给出,FROM关键字指出从其中检索数据的表名。
【结束SQL语句】多条SQL语句必须以分号(;)分隔。MySQL如同多数DBMS一样,不需要在单条SQL语句后加分号。如果你使用的是mysql命令行,必须加上分号来结束SQL语句。(事实上,即使不一定需要,但加上分号肯定没有坏处。)
【SQL语句和大小写】请注意,SQL语句不区分大小写,因此SELECT与select是相同的。
但许多SQL开发人员喜欢对所有SQL关键字使用大写,而对所有列和表名使用小写,这样做使代码更易于阅读和调试。
【使用空格】在处理SQL语句时,其中所有空格都被忽略。SQL语句可以在一行上给出,也可以分成许多行。多数SQL开发人员认为将SQL语句分成多行更容易阅读和调试(例如上面的语句分成了两行,其实一行也ok)。
检索多个列
在SELECT关键字后给出多个列名,列名之间必须以逗号分隔(一定要在列名之间加上逗号,但最后一个列名后不加)。
SELECT prod_name, prod_name, prod_price FROM products;
【数据表示】从上述输出可以看到,SQL语句一般返回原始的、无格式的数据。数据的格式化是一个表示问题,而不是一个检索问题。
检索所有列
这可以通过在实际列名的位置使用星号(*)通配符来达到。
SELECT *FROM products;
PS: 一般,除非你确实需要表中的每个列,否则最好别使用*通配符。虽然使用通配符可能会使你自己省事,不用明确列出所需列,但检索不需要的列通常会降低检索和应用程序的性能
检索不同的行
正如所见,SELECT返回所有匹配的行。但是,如果你不想要每个值每次都出现,怎么办?(例如,你查看商品价格,有10个14元,1个12元,你不想知道有几个,只想知道有多少元的)解决办法是使用DISTINCT
关键字,顾名思义,此关键字指示MySQL只返回不同的值。
SELECT DISTINCT vend_idFROM products;
【注意事项】1、DISTINCT关键字,它必须直接放在列名的前面。
2、DISTINCT关键字应用于所有列而不仅是前置它的列。如果给出SELECT DISTINCT vend_id, prod_price,除非指定的两个列都不同,否则所有行都将被检索出来。即:没法部分使用DISTINCT
3 限制结果(LIMIT子句)
SELECT语句返回所有匹配的行,它们可能是指定表中的每个行。为了返回第一行或前几行,可使用LIMIT子句。
SELECT prod_nameFROM productsLIMIT 5;
此语句使用SELECT语句检索单个列。LIMIT 5指示MySQL返回不多于5行。
SELECT prod_nameFROM productsLIMIT 5, 5;
LIMIT 5, 5指示MySQL返回从行5(第四行)开始的5行。第一个数为开始位置,第二个数为要检索的行数。
【注意】行0检索出来的第一行为行0而不是行1。因此,LIMIT 1, 1将检索出第二行而不是第一行。并且MySQL 5支持LIMIT的另一种替代语法。LIMIT4 OFFSET 3意为从行3(第二行)开始取4行,就像LIMIT 3, 4一样。
4 使用完全限定的表名
迄今为止使用的SQL例子只通过列名引用列。也可能会使用完全限定的名字来引用列(同时使用表名和列字)同时,表名也可以是完全限定的,如下所示:
SELECT products.prod_nameFROM crashcourse.products;
这条SQL语句在功能上等于本章最开始使用的那一条语句。
5 排序检索数据
【定义】子句(clause) SQL语句由子句构成,有些子句是必需的,而有的是可选的。一个子句通常由一个关键字和所提供的数据组成。子句的例子:SELECT语句的FROM子句。
为了明确地排序用SELECT语句检索出的数据,可使用ORDER BY
子句。ORDER BY子句取一个或多个列的名字,据此对输出进行排序。
SELECT prod_name, prod_price, prod_nameFROM productsORDER BY prod_name;
这条语句除了指示MySQL对prod_name列以字母顺序排序数据的ORDER BY子句外,与前面的语句相同。
按多个列排序
为了按多个列排序,只要指定列名,列名之间用逗号分开即可(就像选择多个列时所做的那样)。
SELECT prod_name, prod_price, prod_nameFROM productsORDER BY prod_price , prod_name;
这段代码代码检索3个列,并按其中两个列对结果进行排序——首先按价格,然后再按名称排序。
指定排序方向(找最值)
数据排序不限于升序排序(从A到Z)。这只是默认的排序顺序,还可以使用ORDER BY子句以降序(从Z到A)顺序排序。为了进行降序排序,必须指定DESC
关键字。
SELECT prod_name, prod_price, prod_nameFROM productsORDER BY prod_price DESC, prod_name;
【降序】DESC关键字只应用到直接位于其前面的列名。在上例中,只对prod_price列指定DESC,对prod_name列不指定。因此,prod_price列以降序排序,而prod_name列(在每个价格内)仍然按标准的升序排序。因此,如果想在多个列上进行降序排序,必须对每个列指定DESC关键字。
【升序】与DESC相反的关键字是ASC(ASCENDING),在升序排序时可以指定它。但实际上,ASC没有多大用处,因为升序是默认的(如果既不指定ASC也不指定DESC,则假定为ASC)。
【区分大小写】在字典(dictionary)排序顺序中,A被视为与a相同,这是MySQL(和大多数数据库管理系统)的默认行为。
【案例】使用ORDER BY
和LIMIT
的组合,能够找出一个列中最高或最低的值。
第四章 过滤数据
1 使用WHERE子句
在SELECT
语句中,数据根据WHERE
子句中指定的搜索条件进行过滤。
WHERE子句在表名(FROM子句)之后给出。
SELECT prod_name, prod_price, prod_nameFROM productsWHERE prod_price = 2.50;
【WHERE的位置】在同时使用ORDER BY
和WHERE
子句时,应该让ORDER BY
位于WHERE
之后,否则将会产生错误。
2 WHERE子句操作符
就是跟上文中的=
一样的操作符
检查单个值
【注意】MySQL在执行匹配时默认不区分大小写
SELECT prod_name, prod_price, prod_nameFROM productsWHERE prod_name = 'fuses';
【引号的使用】单引号用来限定字符串。如果将值与串类型的列进行比较,则需要限定引号。用来与数值列进行比较的值不用引号。
不匹配检查
SELECT prod_name, prod_price, prod_nameFROM productsWHERE prod_id <> 1003;
范围值检查
在使用BETWEEN时,必须指定两个值——所需范围的低端值和高端值。这两个值必须用AND关键字分隔。BETWEEN匹配范围中所有的值,包括指定的开始值和结束值。
SELECT prod_name, prod_price, prod_nameFROM productsWHERE prod_price BETWEEN 5 AND 10;
空值检查
在创建表时,表设计人员可以指定其中的列是否可以不包含值。在一个列不包含值时,称其为包含空值NULL。
SELECT语句有一个特殊的WHERE子句,可用来检查具有NULL值的列。这个WHERE子句就是IS NULL
子句。
SELECT prod_name, prod_price, prod_nameFROM productsWHERE prod_price IS NULL;
NULL 无值(no value),它与字段包含0、空字符串或仅仅包含空格不同。
3 组合WHERE子句
AND操作符
为了通过不止一个列进行过滤,可使用AND操作符给WHERE子句附加条件。
SELECT prod_name, prod_price, prod_nameFROM productsWHERE vend_id = 1003 AND prod_price <= 10;
AND 用在WHERE子句中的关键字,用来指示检索满足所有给定条件的行。还可以添加多个过滤条件,每添加一条就要使用一个AND。
OR操作符
SELECT prod_name, prod_price, prod_nameFROM productsWHERE vend_id = 1003 OR vend_id = 1004;
OR用在WHERE子句中使用的关键字,用来表示检索匹配任一给定条件的行。
()操作符–计算次序
WHERE可包含任意数目的AND和OR操作符。允许两者结合以进行复杂和高级的过滤。SQL(像多数语言一样)在处理OR操作符前,优先处理AND操作符,因此一定要记得使用圆括号明确地分组相应的操作符。
SELECT prod_name, prod_price, prod_nameFROM productsWHERE (vend_id = 1003 OR vend_id = 1004) AND prod_price >= 10;
IN操作符
IN操作符用来指定条件范围,范围中的每个条件都可以进行匹配。IN取合法值的由逗号分隔的清单,全都括在圆括号中。
SELECT prod_name, prod_price, prod_nameFROM productsWHERE vend_id IN (1002, 1003);ORDER BY prod_name;
IN在WHERE子句中用来指定要匹配值的清单的关键字,功能与OR相当。但比OR执行更快,并且可以包含其他SELECT语句,使得能够更动态地建立WHERE子句。
NOT操作符
WHERE子句中的NOT操作符有且只有一个功能,那就是否定它之后所跟的任何条件。
SELECT prod_name, prod_price, prod_nameFROM productsWHERE vend_id NOT IN (1002, 1003);ORDER BY prod_name;
4 用通配符进行过滤
LIKE操作符
利用通配符可创建比较特定数据的搜索模式。在这个例子中,如果你想找出名称包含anvil的所有产品,可构造一个通配符搜索模式,找出产品名中任何位置出现anvil的产品。
【定义1】通配符(wildcard) 用来匹配值的一部分的特殊字符。
【定义2】搜索模式(search pattern)由字面值、通配符或两者组合构成的搜索条件。
为在搜索子句中使用通配符,必须使用LIKE
操作符。LIKE指示MySQL,后跟的搜索模式利用通配符匹配而不是直接相等匹配进行比较。
【定义3】谓词(predicate)。当有人提问到操作符何时不是操作符?答案是在它作为谓词时。从技术上说,LIKE是谓词而不是操作符,虽然最终的结果是相同的。
百分号(%)通配符
最常使用的通配符是百分号(%)。在搜索串中,%表示任何字符出现任意次数。%代表搜索模式中给定位置的0个、1个或多个字符。
SELECT prod_id, prod_nameFROM productsWHERE prod_name LIKE 'jet%';
此例子使用了搜索模式'jet%'
。在执行这条子句时,将检索任意以jet
起头的词。
根据MySQL的配置方式,搜索可以是区分大小写的。如果区分大小写,'jet%'与JetPack 1000将不匹配。
SELECT prod_id, prod_nameFROM productsWHERE prod_name LIKE '%anvil%';
搜索模式'%anvil%'
表示匹配任何位置包含文本anvil
的值,而不论它之前或之后出现什么字符。
【注意】1、尾空格可能会干扰通配符匹配。例如,在保存词anvil 时,如果它后面有一个或多个空格,则子句WHERE prod_name LIKE '%anvil’将不会匹配它们,因为在最后的l后有多余的字符。解决这个问题的一个简单的办法是在搜索模式最后附加一个%。一个更好的办法是使用函数(第11章将会介绍)去掉首尾空格。
2、虽然似乎%通配符可以匹配任何东西,但有一个例外,即NULL。
下划线(_)通配符
下划线的用途与%一样,但下划线只匹配单个字符而不是多个字符。
SELECT prod_id, prod_nameFROM productsWHERE prod_name LIKE '_ ton anvil';
与%能匹配0个字符不一样,_总是匹配一个字符,不能多也不能少。
使用通配符的技巧
1、 不要过度使用通配符(这个花时间很长)。如果其他操作符能达到相同的目的,应该使用其他操作符。
2、在确实需要使用通配符时,除非绝对有必要,否则不要把它们用在搜索模式的开始处。把通配符置于搜索模式的开始处,搜索起来是最慢的。
3、仔细注意通配符的位置。如果放错地方,可能不会返回想要的数据。
5 用正则表达式进行搜索
正则表达式是用来匹配文本的特殊的串(字符集合)。
正则表达式用正则表达式语言来建立,正则表达式语言是用来完成刚讨论的所有工作以及更多工作的一种特殊语言。与任意语言一样,正则表达式具有你必须学习的特殊的语法和指令。
【使用MySQL正则表达式】正则表达式的作用是匹配文本,将一个模式(正则表达式)与一个文本串进行比较。MySQL用WHERE
子句对正则表达式提供了初步的支持,允许你指定正则表达式,过滤SELECT
检索出的数据。
基本字符匹配(REGEXP关键字)
下面的语句检索列prod_name包含文本1000的所有行:
SELECT prod_nameFROM productsWHERE prod_name REGEXP '1000';
(看似与LIKE相同)其实它告诉MySQL:REGEXP后所跟的东西作为正则表达式(与文字正文1000匹配的一个正则表达式)处理。
MySQL中的正则表达式匹配不区分大小写(即,大写和小写都匹配)。为区分大小写,可使用
BINARY
关键字,如:WHERE prod_name REGEXP BINARY 'JetPack .000'
正则表达式中的一个特殊符号(.)
SELECT prod_nameFROM productsWHERE prod_name REGEXP '.000';ORDER BY prod_name;
它表示匹配任意一个字符,相当于LIKE里面的(_)。
LIKE与REGEXP的区别
主要体现在不用通配符时(LIKE
匹配整个串而REGEXP
匹配子串):
WHERE prod_name LIKE '1000';//不返回数据WHERE prod_name REGEXP '1000';//返回一行
返回的一行为:
LIKE匹配整个列(即内容完全一样才可以)。如果被匹配的文本在列值中出现,LIKE将不会找到它,相应的行也不被返回。
而REGEXP在列值内进行匹配(即内容为字串即可),如果被匹配的文本在列值中出现,REGEXP将会找到它,相应的行将被返回。
不过,虽然它们存在区别,但是REGEXP也是可以用来匹配整个列值的(从而起与LIKE相同的作用)——使用^
和$
定位符(anchor)即可。
进行OR匹配
为搜索两个串之一(或者为这个串,或者为另一个串),使用|
符号。如:
SELECT prod_nameFROM productsWHERE prod_name REGEXP '1000|2000|3000';ORDER BY prod_name;
匹配几个字符之一(另一种形式的OR语句)
可通过指定一组用[和]
括起来的字符来完成只匹配特定的字符。
SELECT prod_nameFROM productsWHERE prod_name REGEXP '[123] Ton';ORDER BY prod_name;
这里,使用了正则表达式[123] Ton
。[123]
定义一组字符,它的意思是匹配1或2或3,因此,1 ton
、2 ton
和3 ton
都匹配且返回)。事实上,正则表达式[123]Ton
为[1|2|3]Ton
的缩写,也可以使用后者来表示。
在集合的开始处放置一个
^
表示否定,即[^123] Ton
表示除了1、2、3以外带Ton的东西
匹配范围
集合可用来定义要匹配的一个或多个字符。如[0-9]将匹配数字0到9。此外,范围不一定只是数值的,[a-z]匹配任意字母字符。
SELECT prod_nameFROM productsWHERE prod_name REGEXP '[1-5] Ton';ORDER BY prod_name;
匹配特殊字符
为了匹配特殊字符,必须用\\
为前导。如\\-
表示查找-
,\\.
表示查找.
。(为了匹配反斜杠\
字符本身,需要使用\\\
。)
【定义】这种处理就是所谓的转义(escaping),正则表达式内具有特殊意义的所有字符都必须以这种方式转义。
\\
也用来引用元字符(具有特殊含义的字符),如下表所列。
多数正则表达式实现使用单个反斜杠转义特殊字符,以便能使用这些字符本身。但MySQL要求两个反斜杠(MySQL自己解释一个,正则表达式库解释另一个)。
匹配字符类
存在找出你自己经常使用的数字、所有字母字符或所有数字字母字符等的匹配。可以使用预定义的字符集。
匹配多个实例
可以用下表列出的正则表达式重复元字符来完成。
【案例1】下面的\\([0-9] sticks?\\)
里,首先\\(
是正则表达式中的(
后面的\\)
同理;其次,[0-9]
匹配任意数字(这个例子中为1和5),而最后就是我们的元字符?
,sticks?
匹配stick
和sticks
(s
后的?
使s
可选,因为?
匹配它前面的任何字符的0次或1次出现)
【案例2】[:digit:]
匹配任意数字,因而它为数字的一个集合。{4}
确切地要求它前面的字符(任意数字)出现4次,所以[[:digit:]]{4}
匹配连在一起的任意4位数字。
定位符
为了匹配特定位置的文本,需要用到下表的定位符。而这里的^
和$
可以使REGEXP的作用与LIKE一样。
^有两种用法。在集合中(用[和]定义),用它来否定该集合,否则,用来指串的开始处。
SELECT prod_nameFROM productsWHERE prod_name REGEXP '^[0-9\\.]';ORDER BY prod_name;
其中^[0-9\\.]
只在.
或任意数字为串中第一个字符时才匹配它们(为什么是点或数字,是因为[]
符号——可见匹配几个字符之一的内容)。
第五章 创建计算字段
1 计算字段
存储在数据库表中的数据一般不是应用程序所需要的格式。而计算字段便可以直接从数据库中检索出转换、计算或格式化过的数据;计算字段是运行时在SELECT语句内创建的。
2 计算字段常用函数
拼接字段
解决办法是把两个列拼接起来。在MySQL的SELECT
语句中,可使用Concat()
函数来拼接两个列。
多数DBMS使用
+
或||
来实现拼接,MySQL则使用Concat()函数来实现。当把SQL语句转换成MySQL语句时一定要把这个区别铭记在心。
SELECT Concat(prod_name, '(', prod_country, ')') FROM productsORDER BY prod_name;
Concat()
拼接串,即把多个串连接起来形成一个较长的串。Concat()
需要一个或多个指定的串,各个串之间用逗号
分隔。此时返回的检索内容,是经过处理后的计算字段。
删除数据两侧多余的空格
RTrim()
函数来完成删除右侧多余的空格;LTrim()
去掉串左侧多余的空格;Trim()
去掉串左右两边的空格。
SELECT Concat(RTrim(prod_name), '(', Rtrim(prod_country), ')') FROM productsORDER BY prod_name;
使用别名
上面也提到过,计算字段是新创建的,其并不是实际的表列,那么客户机需要引用,便需要给其取一个名字。(其他用途:常见的用途包括在实际的表列名包含不符合规定的字符(如空格)时重新命名它,在原来的名字含混或容易误解时扩充它,等等。)
【定义】别名(alias)是一个字段或值的替换名。有时也称为导出列(derived column),别名用AS
关键字赋予。
SELECT Concat(prod_name, '(', prod_country, ')') AS pord_titleFROM productsORDER BY prod_name;
它指示SQL创建一个包含指定计算的名为pord_title
的计算字段。任何客户机应用都可以按名引用这个列,就像它是一个实际的表列一样。
3 执行算术计算
计算字段的另一常见用途是对检索出的数据进行算术计算。
SELECT prod_name,quantity,item_price,quantity * item_price AS expanded_priceFROM products
输出中显示的expanded_price
列为一个计算字段,此计算为quantity∗itempricequantity*item_{price}quantity∗itemprice。客户机应用现在可以使用这个新计算列,就像使用其他列一样。
第六章 使用数据处理函数
1 函数
函数一般是在数据上执行的,它给数据的转换和处理提供了方便。但函数的可移植性并不好,因此如果你决定使用函数,应该保证做好代码注释。
2 使用函数
文本处理函数
常用的文本处理函数如下:
其中,SOUNDEX是一个将任何文本串转换为描述其语音表示的字母数字模式的算法。
常用的日期和时间处理函数
日期和时间采用相应的数据类型和特殊的格式存储,以便能快速和有效地排序或过滤,并且节省物理存储空间。
在使用时,首先需要注意的是MySQL使用的日期格式:日期必须为格式yyyy-mm-dd
。
【案例1】提取订单记录的order_date为-09-01
的行:
SELECT cust_id,FROM ordersWHERE DATA(order_data) = '-09-01';
此处用DATA的原因是:若没有DATA,而存 储 的 order_date 值 为-09-01 11:30:05
,则直接WHERE order_date = '-09-01'
会匹配失败。
【案例2】检索出9月下的所有订单:
SELECT cust_id,FROM ordersWHERE Year(order_data) = '' AND Month(order_data) = 9;
数值处理函数
这些函数一般主要用于代数、三角或几何运算,因此没有串或日期—时间处理函数的使用那么频繁。
常用数值处理函数如下:
第七章 汇总数据
1 聚集函数(也是返回计算字段,建议别名化)
【定义】聚集函数(aggregate function) 运行在行组上,计算和返回单个值的函数。
【案例】合计每项物品的item_price*quantity
,得出总的订单金额:
SELECT SUM(quantity * item_price) AS total_priceFROM products
故SUM()也可以用来合计计算值。
利用标准的算术操作符,所有聚集函数都可用来执行多个列上的计算。
2 聚集不同的值
以上5个聚集函数都可以如下使用:
对所有的行执行计算,指定ALL参数或不给参数(因为ALL是默认行为)只包含不同的值,指定DISTINCT参数
【案例】当平均值只考虑各个不同的价格:
SELECT AVG(DISTINCT item_price) AS avg_priceFROM products
【易错点】DISTINCT必须使用列名,不能用于计算或表达式。因此不能用于COUNT(*)
即不允许出现COUNT(DISTINCT)
3 组合聚集函数
SELECT语句可根据需要包含多个聚集函数。这样就返回多个列
【案例】输入为:
而输出为:
第八章 分组数据
1 数据分组
分组允许把数据分为多个逻辑组,以便能对每个组进行聚集计算。
2 创建分组
分组是在SELECT
语句的GROUP BY
子句中建立的。
SELECT vend_id, COUNT(*) AS num_prodsFROM productsGROUP BY vend_id;
上面的SELECT语句指定了两个列,vend_id包含产品供应商的ID,num_prods为计算字段(用COUNT(*)函数建立)。
GROUP BY
子句指示MySQL按vend_id
排序并分组数据。这导致对每个vend_id
而不是整个表计算num_prods
一次。从输出中可以看到,供应商1001有3个产品,供应商1002有2个产品,供应商1003有7个产品,而供应商1005有2个产品。
在具体使用GROUP BY子句前,需要知道一些重要的规定:
GROUP BY子句可以包含任意数目的列。但是在建立分组时,指定的所有列都一起计算,不可以从个别列去取数据。GROUP BY子句中列出的每个列都必须是检索列或有效的表达式(但不能是聚集函数)。如果在SELECT中使用表达式,则必须在GROUP BY子句中指定相同的表达式。不能使用别名。如果分组列中具有NULL值,则NULL将作为一个分组返回。如果列中有多行NULL值,它们将分为一组。【位置】GROUP BY子句必须出现在WHERE子句之后,ORDER BY子句之前。
使用WITH ROLLUP关键字,可以得到每个分组以及每个分组汇总级别(针对每个分组)的值。如
GROUP BY vend_id WITH ROLLUP
;
3 过滤分组
MySQL允许过滤分组,规定包括哪些分组,排除哪些分组。
MySQL为此目的提供了另外的子句,那就是HAVING
子句。WHERE子句都可以用HAVING来替代。唯一的差别是WHERE过滤行,而HAVING过滤分组。
【案例1】列出至少有两个订单的所有顾客
SELECT vend_id, COUNT(*) AS num_prodsFROM productsGROUP BY vend_idHAVING COUNT(*) >= 2;
有时候,WHERE和HAVING可能会同时出现,如
【案例2】列出具有2个(含)以上、价格为10(含)以上的产品的供应商
SELECT vend_id, COUNT(*) AS num_prodsFROM productsWHERE prod_price >= 10GROUP BY vend_idHAVING COUNT(*) >= 2;
4 GROUP BY和ORDER BY的区别
一般在使用GROUP BY子句时,应该也给出ORDER BY子句。这是保证数据正确排序的唯一方法。
第九章 嵌套查询
1 使用子查询
SQL还允许创建子查询(subquery),即嵌套在其他查询中的查询。
利用子查询进行过滤
在SELECT语句中,子查询总是从内向外处理。
以一个案例为准:一共有三个表:
orders表存储每个订单的订单号、客户ID、订单日期。
orderitems表存储各订单的物品。
customers表存储客户的ID所对应的客户信息。
【案例】需要列出订购物品TNT2的所有客户。在这里我们使用子查询将对三个表的查询组合成一个语句。(下章的联结可以更好地做到)
SELECT cust_name, cust_contact FROM customersWHERE cust_id IN (SELECT cust_idFROM ordersWHERE order_num IN (SELECT order_numFROM orderitemsWHERE prod_id = 'TNT2'));
在WHERE子句中使用子查询能够编写出功能很强并且很灵活的SQL语句。对于能嵌套的子查询的数目没有限制,不过在实际使用时由于性能的限制,不能嵌套太多的子查询。
作为计算字段使用子查询
使用子查询的另一方法是创建计算字段。
【案例】显示customers表中每个客户的订单总数。
从customers表中检索客户列表。对于检索出的每个客户,统计其在orders表中的订单数目。
SELECT cust_name,cust_state,(SELECT COUNT(*)FROM ordersWHERE orders.cust_id = customers.cust_id) AS orders FROM customersORDER BY cust_name ;
这里用到了第四章的《完全限定的表名》这种类型的子查询称为相关子查询。
【定义】相关子查询(correlated subquery) 涉及外部查询的子查询。
输出结果如下:
2 联结表
联结
【定义1】关系表的设计就是要保证把信息分解成多个表,一类数据一个表。
各表通过某些常用的值(即关系设计中的关系(relational))互相关联。就如同上一张的题目,根据客户信息,其customers和orders是关系表。
【定义2】外键(foreign key)为某个表中的一列,它包含另一个表的主键值,定义了两个表之间的关系。
【定义3】可伸缩性(scale)能够适应不断增加的工作量而不失败。设计良好的数据库或应用程序称之为可伸缩性好(scale well)。而关系数据库的可伸缩性远比非关系数据库要好。
【定义4】联结是一种机制,用来在一条SELECT语句中关联表,因此称之为联结。
创建联结
联结的创建非常简单,规定要联结的所有表以及它们如何关联即可。
SELECT prod_name,prod_price, vend_nameFROM vendors, productsWHERE vendors.vend_id = products.vend_idORDER BY vend_name, prod_name;
注意这里的SELECT
中的三个列共属于两个表中,而FROM
便指明了这条SELECT
语句联结的两个表的名字。【关键】这两个表用WHERE
子句正确联结,WHERE子句指示MySQL匹配vendors
表中的vend_id
和products
表中的vend_id
。其中由于存在二义性,因此必须使用《完全限定列名》。
但若没有联结条件的两个表强行用上面的SELECT和FROM进行联结,结果就是会返回笛卡尔积。
【定义】笛卡儿积(cartesian product)由没有联结条件的表关系返回的结果为笛卡儿积。检索出的行的数目将是第一个表中的行数乘以第二个表中的行数。
PS:因此应该保证所有联结都有WHERE子句,否则MySQL将返回比想要的数据多得多的数据。
使用联结和联结条件
注意所使用的联结类型。一般我们使用内部联结,但使用外部联结也是有效的。应该总是提供联结条件,否则会得出笛卡儿积。在一个联结中可以包含多个表,甚至对于每个联结可以采用不同的联结类型。3 内部联结(相比WHERE首选INNER JOIN语法)
上面的联结称为等值联结(equijoin),它基于两个表之间的相等测试。这种联结也称为内部联结。也可使用INNER JOIN
来代替WHERE来创造联结。如下面语句等同于上面的语句:
SELECT prod_name,prod_price, vend_nameFROM vendors INNER JOIN productsON vendors.vend_id = products.vend_id;
这里,两个表之间的关系是FROM子句的组成部分,以INNER JOIN指定。在使用这种语法时,联结条件用特定的ON子句而不是WHERE子句给出。传递给ON的实际条件与传递给WHERE的相同。
联结多个表
SQL对一条SELECT语句中可以联结的表的数目没有限制。创建联结的基本规则也相同。
【案例】正如第14章所述,子查询并不总是执行复杂SELECT操作的最有效的方法,下面是使用联结的相同查询:需要列出订购物品TNT2的所有客户。
SELECT cust_name, cust_contact FROM customers, orders, orderitemsWHERE customers.cust_id = orders.cust_idAND orders.order_num = orderitems.order_numAND prod_id = 'TNT2';
这里有3个WHERE子句条件。前两个关联联结中的表,后一个过滤产品TNT2的数据。
使用表别名
别名除了用于列名和计算字段外,SQL还允许给表名起别名。
SELECT cust_name, cust_contact FROM customers AS c, orders AS o, orderitems AS oiWHERE c.cust_id = o.cust_idAND o.order_num = oi.order_numAND prod_id = 'TNT2';
在此例子中,表别名只用于WHERE子句。但是,表别名不仅能用于WHERE子句,它还可以用于SELECT的列表、ORDER BY子句以及语句的其他部分。
【注意与列别名的区别】表别名只在查询执行中使用,表别名不返回到客户机。
4 使用不同类型的联结
前面的只是内部联结或等值联结(equijoin)的简单联结,还有三种高级联结:
自联结
【案例】假如你发现某物品(其ID为DTNTR)存在问题,因此想知道生产该物
品的供应商生产的其他物品是否也存在这些问题。(而根据ID找到供货商和根据供货商找到所有的ID是在同一个表下的)
SELECT p1.prod_id, p1.prod_name FROM products AS p1, products AS p2WHERE p1.vend_id = p2.vend_idAND p2.prod_id = 'DTNTR';
SELECT语句使用p1前缀明确地给出所需列的全名。如果不这样,MySQL将返回错误,因为分别存在两个名为prod_id、prod_name的列。MySQL不知道想要的是哪一个列(即使它们事实上是同一个列)。【步骤】WHERE(通过匹配p1中的vend_id和p2中的vend_id)首先联结两个表,然后按第二个表中的prod_id过滤数据,返回所需的数据(即便他们是同一个表)。
【通常用自联结而不用子查询】自联结通常作为外部语句用来替代从相同表中检索数据时使用的子查询语句。
自然联结
标准的联结(前一章中介绍的内部联结)返回所有数据,甚至相同的列多次出现。自然联结排除多次出现,使每个列只返回一次(毕竟有联结关系的表可能不止一列有关系,可能多个列都有关系,都存在重复)。
事实上,迄今为止我们建立的每个内部联结都是自然联结,很可能我们永远都不会用到不是自然联结的内部联结。
外部联结(关键字OUTER JOIN)
许多联结将一个表中的行与另一个表中的行相关联。但有时候会需要包含没有关联行的那些行。联结包含了那些在相关表中没有关联行的行。这种类型的联结称为外部联结。
例如:
对每个客户下了多少订单进行计数,包括那些至今尚未下订单的客户列出所有产品以及订购数量,包括没有人订购的产品计算平均销售规模,包括那些至今尚未下订单的客户
与内部联结不同的是,外部连接需要用FROM
中的关键字OUTER JOIN
来指定联结的类型,并且在使用OUTER JOIN
语法时,必须使用RIGHT
或LEFT
关键字指定包括其所有行的表(RIGHT指出的是OUTER JOIN右边的表,而LEFT指出的是OUTER JOIN左边的表)。
【案例】
SELECT customer.cust_id, orders.order_num FROM customer LEFT OUTER JOIN ordersON customer.cust_id = orders.cust_id;
5 使用带聚集函数的联结
【案例】检索所有客户及每个客户下的订单数
SELECT customer.cust_name, customer.cust_id, COUNT(orders.order_num) AS num_ord FROM customer LEFT OUTER JOIN ordersON customer.cust_id = orders.cust_idGROUP BY customer.cust_id;
此SELECT语句使用INNER JOIN将customers和orders表互相关联。GROUP BY
子句按客户分组数据,因此,函数调用COUNT (orders.order_num)
对每个客户的订单计数,将它作为num_ord
返回。
第十章 组合查询
MySQL也允许执行多个查询(多条SELECT语句),并将结果作为单个查询结果集返回。这些组合查询通常称为并(union)或复合查询(compound query)。以下两种需要使用组合查询:
在单个查询中从不同的表返回类似结构的数据对单个表执行多个查询,按单个查询返回数据
1 创建查询
可用UNION
操作符来组合数条SQL查询。
使用UNION
UNION的使用很简单。所需做的只是给出每条SELECT语句,在各条语句之间放上关键字UNION。
【案例】假如需要价格小于等于5的所有物品的一个列表,而且还想包括供应商1001和1002生产的所有物品(不考虑价格)——该题其实也可以靠WHERE
和OR
配合完成,但 这里用UNION
解决!
SELECT vend_id, prod_id, prod_priceFROM productsWHERE prod_price <=5 ;UNIONSELECT vend_id, prod_id, prod_priceFROM productsWHERE vend_id IN (1001, 1002);
【PS】虽然本例是对单个表用UNION,但是对多个表同样可以UNION返回成一个结果
UNION规则
UNION必须由两条或两条以上的SELECT语句组成,语句之间用关键字UNION分隔UNION中的每个查询必须包含相同的列、表达式或聚集函数列数据类型必须兼容:类型不必完全相同,但必须是DBMS可以隐含地转换的类型(例如,不同的数值类型或不同的日期类型)2 包含或取消重复的行
UNION
从查询结果集中自动去除了重复的行(换句话说,它的行为与单条SELECT
语句中使用多个WHERE
子句条件一样)。
如果想返回所有匹配行,可使用UNION ALL
而不是UNION
。
3 对组合查询结果排序
在用UNION组合查询时,只能使用一条ORDER BY
子句,它必须出现在最后一条SELECT
语句之后。
第十一章 全文本搜索
在使用全文本搜索时,MySQL不需要分别查看每个行,不需要分别分析和处理每个词。
其只需要创建指定列中各词的一个索引,搜索可以针对这些词进行。
1 使用全文本搜索
为了进行全文本搜索,必须索引被搜索的列,而且要随着数据的改变不断地重新索引(这个过程MySQL会自动地进行)。
启用全文本搜索支持
一般在创建表时启用全文本搜索。CREATE TABLE
语句接受FULLTEXT
子句,该子句给出被索引列的一个逗号分隔的列表。如FULLTEXT(note_text)
则先对note_text的列进行索引,以便后序对该列进行全文本搜索。
PS:不要在导入数据时使用FULLTEXT
,毕竟每次重新索引都耗费时间。
进行全文本搜索支持(搜索不区分大小写)
在索引之后,结合WHERE
关键字使用两个函数Match()
和Against()
执行全文本搜索,其中Match()
指定被搜索的列,Against()
指定要使用的搜索表达式。
SELECT note_textFROM productnotesWHERE Match(note_text) Against('rabbit');
【三点注意】1、Match
需要严格与当初定义的FULLTEXT
内容一样,如果指定多个列,则必须列出它们(而且次序正确)
2、除非使用BINARY方式,否则全文本搜索不区分大小写
3、虽然上面用WHERE
+LIKE'%rabbit%'
也能办到,但速度慢,并且其返回的次序不同,全文本搜索的一个重要部分就是以文本匹配的良好程度对结果排序,具有较高等级的行先返回!
2使用查询扩展
查询扩展用来设法放宽所返回的全文本搜索结果的范围。
在使用查询扩展时,MySQL对数据和索引进行两遍扫描来完成搜索:
进行一个基本的全文本搜索,找出与搜索条件匹配的所有行MySQL检查这些匹配行并选择所有有用的词MySQL再次进行全文本搜索,这次不仅使用原来的条件,而且还使用所有有用的词。
实现通过在Against()
函数里面加入关键字WITH QUERY EXPANSION
SELECT note_textFROM productnotesWHERE Match(note_text) Against('rabbit' WITH QUERY EXPANSION);
3 布尔文本搜索(更细致地查找)
MySQL支持全文本搜索的另外一种形式,称为布尔方式(boolean mode)。该方式即使没有定义FULLTEXT索引,也可以使用该方式进行搜索。但这是一种非常缓慢的操作。
【案例】为了匹配包含heavy但不包含任意以rope开始的词的行,可使用以下查询:
SELECT note_textFROM productnotesWHERE Match(note_text) Against('heavy -rope*' IN BOOLEAN MODE);
其中,-rope*
明确地指示MySQL排除包含rope*
。
下标将列出所有布尔操作符(操作符都应该放在每个词的前面)
【案例–易错点】注意这个案例,若没有指定操作符时,空格表示或的意思:
SELECT note_textFROM productnotesWHERE Match(note_text) Against('heavy rope' IN BOOLEAN MODE);
这个搜索匹配包含heavy和rope至少一个词的行!
SELECT note_textFROM productnotesWHERE Match(note_text) Against('"heavy rope"' IN BOOLEAN MODE);
这个才是搜索heavy rope这个词!
排列而不排序:在布尔方式中,不按等级值降序排序返回的行。
4 全文本搜索的使用说明
在索引全文本数据时,短词被忽略且从索引中排除。短词定义为那些具有3个或3个以下字符的词MySQL带有一个内建的非用词(stopword)列表,这些词在索引全文本数据时总是被忽略。许多词出现的频率很高,搜索它们没有用处(返回太多的结果)。因此,MySQL规定了一条50%规则,但并不适用于IN BOOLEAN MODE。如果表中的行数少于3行,则全文本搜索不返回结果。(理由为第三条)忽略词中的单引号。例如,don’t索引为dont。不具有词分隔符(包括日语和汉语)的语言不能恰当地返回全文本搜索结果。仅在MyISAM数据库引擎中支持全文本搜索如果觉得《《MySQL必知必会》学习笔记之“数据库的检索”》对你有帮助,请点赞、收藏,并留下你的观点哦!