《MySQL必知必会》学习笔记

第1章 了解MySql

1.1 数据库基础

1.1.1 什么是数据库

数据库 db(datebase)是保存有组织的数据的容器。我们直接使用的如MySQL其实不是数据库而是数据库软件 dbms:datebase Management System)。我们不直接访问数据库而是通过数据库软件来访问数据库

1.1.2 表

某种特定数据类型的结构化清单,

数据库中每张表的名字是唯一的。

1.1.3 列和数据类型

理解为键名

1.1.4 行

每条数据

1.1.5 主键
  • 主键本身是一列(或一组列),其值能够唯一区分表中每行
  • 表可以没有主键
  • 若有主键则必须满足一下2个条件
    • 任意两行不能由相同的主键
    • 每行必须有一个主键,主键不能为NULL
  • 主键的最好习惯
    • 不更新主键列中的值
    • 不重用主键列的值
    • 不在主键中使用可能会更改的值

1.2 什么是SQL

SQL(Structured Query Language)结构化查询语言。是由一个标准委员会制定维护的,基本上通用于市面上的DBMS,但不同的DBMS的SQL语法会略有不同。

第2章 MySQL简介

2.1 什么是MySQL

各种吹牛

2.1.1 客户机—服务器软件

简单的CS模型

2.1.2 MySQL版本

罗列了各版本的区别

2.2 MySQL工具

这里下载MySQL脚本按照附录B的方法导入数据库。

导入之后数据库结构为:

mysql> SHOW COLUMNS FROM customers;
+--------------+-----------+------+-----+---------+----------------+
| Field        | Type      | Null | Key | Default | Extra          |
+--------------+-----------+------+-----+---------+----------------+
| cust_id      | int(11)   | NO   | PRI | NULL    | auto_increment |
| cust_name    | char(50)  | NO   |     | NULL    |                |
| cust_address | char(50)  | YES  |     | NULL    |                |
| cust_city    | char(50)  | YES  |     | NULL    |                |
| cust_state   | char(5)   | YES  |     | NULL    |                |
| cust_zip     | char(10)  | YES  |     | NULL    |                |
| cust_country | char(50)  | YES  |     | NULL    |                |
| cust_contact | char(50)  | YES  |     | NULL    |                |
| cust_email   | char(255) | YES  |     | NULL    |                |
+--------------+-----------+------+-----+---------+----------------+

mysql> SHOW COLUMNS FROM orderitems;
+------------+--------------+------+-----+---------+-------+
| Field      | Type         | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+-------+
| order_num  | int(11)      | NO   | PRI | NULL    |       |
| order_item | int(11)      | NO   | PRI | NULL    |       |
| prod_id    | char(10)     | NO   | MUL | NULL    |       |
| quantity   | int(11)      | NO   |     | NULL    |       |
| item_price | decimal(8,2) | NO   |     | NULL    |       |
+------------+--------------+------+-----+---------+-------+

mysql> SHOW COLUMNS FROM orders;
+------------+----------+------+-----+---------+----------------+
| Field      | Type     | Null | Key | Default | Extra          |
+------------+----------+------+-----+---------+----------------+
| order_num  | int(11)  | NO   | PRI | NULL    | auto_increment |
| order_date | datetime | NO   |     | NULL    |                |
| cust_id    | int(11)  | NO   | MUL | NULL    |                |
+------------+----------+------+-----+---------+----------------+

mysql> SHOW COLUMNS FROM productnotes;
+-----------+----------+------+-----+---------+----------------+
| Field     | Type     | Null | Key | Default | Extra          |
+-----------+----------+------+-----+---------+----------------+
| note_id   | int(11)  | NO   | PRI | NULL    | auto_increment |
| prod_id   | char(10) | NO   |     | NULL    |                |
| note_date | datetime | NO   |     | NULL    |                |
| note_text | text     | YES  | MUL | NULL    |                |
+-----------+----------+------+-----+---------+----------------+

mysql> SHOW COLUMNS FROM products;
+------------+--------------+------+-----+---------+-------+
| Field      | Type         | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+-------+
| prod_id    | char(10)     | NO   | PRI | NULL    |       |
| vend_id    | int(11)      | NO   | MUL | NULL    |       |
| prod_name  | char(255)    | NO   |     | NULL    |       |
| prod_price | decimal(8,2) | NO   |     | NULL    |       |
| prod_desc  | text         | YES  |     | NULL    |       |
+------------+--------------+------+-----+---------+-------+

mysql> SHOW COLUMNS FROM vendors;
+--------------+----------+------+-----+---------+----------------+
| Field        | Type     | Null | Key | Default | Extra          |
+--------------+----------+------+-----+---------+----------------+
| vend_id      | int(11)  | NO   | PRI | NULL    | auto_increment |
| vend_name    | char(50) | NO   |     | NULL    |                |
| vend_address | char(50) | YES  |     | NULL    |                |
| vend_city    | char(50) | YES  |     | NULL    |                |
| vend_state   | char(5)  | YES  |     | NULL    |                |
| vend_zip     | char(10) | YES  |     | NULL    |                |
| vend_country | char(50) | YES  |     | NULL    |                |
+--------------+----------+------+-----+---------+----------------+

第3章 使用MySQL

3.1 链接MySQL

// 链接mysql
~$ mysql -u root -p

// 创建数据库
CREATE DATABASE my_first_sql;

// 展示该服务器的所有数据库
SHOW DATABASES;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| crashcourse        |
| my_first_sql       |
| mysql              |
| performance_schema |
| test               |
+--------------------+
6 rows in set (0.00 sec)

// 打开数据库
USE my_first_sql;
Database changed

// 展示当前数据库里面的表
SHOW TABLES;

// 展示指定表的所有列
SHOW COLUMNS FROM my_first_sql;

第4章 检索数据

4.1 SELECT语句

SELECT 语句需要2个必要信息从哪里查找查找什么

4.2 检索单个列

关键字用大写 表,数据库,行列名用小写。

SELECT prod_name FROM products;
+----------------+
| prod_name      |
+----------------+
| .5 ton anvil   |
| 1 ton anvil    |
| 2 ton anvil    |
| Detonator      |
| Bird seed      |
| Carrots        |
| Fuses          |
| JetPack 1000   |
| JetPack 2000   |
| Oil can        |
| Safe           |
| Sling          |
| TNT (1 stick)  |
| TNT (5 sticks) |
+----------------+

4.3 检索多个列

SELECT cust_id, cust_zip, cust_email FROM customers;
+---------+----------+---------------------+
| cust_id | cust_zip | cust_email          |
+---------+----------+---------------------+
|   10001 | 44444    | ylee@coyote.com     |
|   10002 | 43333    | NULL                |
|   10003 | 42222    | rabbit@wascally.com |
|   10004 | 88888    | sam@yosemite.com    |
|   10005 | 54545    | NULL                |
+---------+----------+---------------------+

4.4 检索所有列

SELECT * FROM products;

4.5 检索不同的行

// 找出不同vend_id的行
SELECT DISTINCT vend_id FROM products;
+---------+
| vend_id |
+---------+
|    1001 |
|    1002 |
|    1003 |
|    1005 |
+---------+

// 找出vend_id 和 prod_price不同的行
SELECT DISTINCT vend_id, prod_price FROM products;
+---------+------------+
| vend_id | prod_price |
+---------+------------+
|    1001 |       5.99 |
|    1001 |       9.99 |
|    1001 |      14.99 |
|    1003 |      13.00 |
|    1003 |      10.00 |
|    1003 |       2.50 |
|    1002 |       3.42 |
|    1005 |      35.00 |
|    1005 |      55.00 |
|    1002 |       8.99 |
|    1003 |      50.00 |
|    1003 |       4.49 |
+---------+------------+

4.6 限制结果

LIMIT可以获取指定序列的行

// 从第1行开始取2行
SELECT vend_id 
FROM vendors 
LIMIT 1, 2;

+---------+
| vend_id |
+---------+
|    1002 |
|    1003 |
+---------+

// LIMIT后只有一个数字 代表取前5行
SELECT vend_id 
FROM vendors 
LIMIT 5;

+---------+
| vend_id |
+---------+
|    1001 |
|    1002 |
|    1003 |
|    1004 |
|    1005 |
+---------+

// 如果满足条件的行数不足,则只会返回不足的结果
SELECT vend_id 
FROM vendors 
LIMIT 5 5;

+---------+
| vend_id |
+---------+
|    1006 |
+---------+

SELECT vend_id 
FROM vendors 
LIMIT 10 5;

Empty set   // 无结果

4.7 使用完全限定的表名

以下几种写法完全等效

SELECT crashcourse.vendors.vend_id 
FROM crashcourse.vendors;

SELECT vendors.vend_id 
FROM crashcourse.vendors;

SELECT vend_id 
FROM crashcourse.vendors;

SELECT crashcourse.vendors.vend_id 
FROM vendors;

SELECT vendors.vend_id 
FROM vendors;

SELECT vend_id 
FROM vendors;

第5章 排序检索数据

5.1 排序数据

// 未排序
SELECT order_item, prod_id
FROM orderitems;

+------------+---------+
| order_item | prod_id |
+------------+---------+
|          1 | ANV01   |
|          2 | ANV02   |
|          4 | ANV03   |
|          4 | FB      |
|          1 | FB      |
|          1 | FC      |
|          1 | JP2000  |
|          2 | OL1     |
|          3 | SLING   |
|          3 | TNT2    |
|          1 | TNT2    |
+------------+---------+

// 以order_item排序
SELECT order_item, prod_id
FROM orderitems
ORDER BY order_item;

+------------+---------+
| order_item | prod_id |
+------------+---------+
|          1 | ANV01   |
|          1 | FB      |
|          1 | FC      |
|          1 | TNT2    |
|          1 | JP2000  |
|          2 | ANV02   |
|          2 | OL1     |
|          3 | TNT2    |
|          3 | SLING   |
|          4 | FB      |
|          4 | ANV03   |
+------------+---------+

// 以order_item,和prod_id进行排序。前者相同的情况下会用后者排序。
SELECT order_item, prod_id
FROM orderitems
ORDER BY order_item, prod_id;

+------------+---------+
| order_item | prod_id |
+------------+---------+
|          1 | ANV01   |
|          1 | FB      |
|          1 | FC      |
|          1 | JP2000  |
|          1 | TNT2    |
|          2 | ANV02   |
|          2 | OL1     |
|          3 | SLING   |
|          3 | TNT2    |
|          4 | ANV03   |
|          4 | FB      |
+------------+---------+

5.3 指定排序方向

倒序排序

SELECT order_item, prod_id
FROM orderitems
ORDER BY order_item DESC, prod_id;

+------------+---------+
| order_item | prod_id |
+------------+---------+
|          4 | ANV03   |
|          4 | FB      |
|          3 | SLING   |
|          3 | TNT2    |
|          2 | ANV02   |
|          2 | OL1     |
|          1 | ANV01   |
|          1 | FB      |
|          1 | FC      |
|          1 | JP2000  |
|          1 | TNT2    |
+------------+---------+

SELECT order_item, prod_id
FROM orderitems
ORDER BY order_item DESC, prod_id DESC;

+------------+---------+
| order_item | prod_id |
+------------+---------+
|          4 | FB      |
|          4 | ANV03   |
|          3 | TNT2    |
|          3 | SLING   |
|          2 | OL1     |
|          2 | ANV02   |
|          1 | TNT2    |
|          1 | JP2000  |
|          1 | FC      |
|          1 | FB      |
|          1 | ANV01   |
+------------+---------+

// 找到最贵的物品
SELECT prod_price 
FROM products
ORDER BY prod_price DESC
LIMIT 1;
+------------+
| prod_price |
+------------+
|      55.00 |
+------------+

第6章 过滤数据

6.1 使用WHERE子句

WHERE 操作符

操作符 说明
= 等于
<> 不等于
!= 不等于
< 小于
<= 小于等于
> 大于
>= 大于等于
BETWEEN … AND ... 两值之间
IS NULL 判空
SELECT vend_id, prod_name
FROM products
WHERE vend_id = 1002;

+---------+-----------+
| vend_id | prod_name |
+---------+-----------+
|    1002 | Fuses     |
|    1002 | Oil can   |
+---------+-----------+

SELECT vend_id, prod_name
FROM products
WHERE vend_id < 1002;

+---------+--------------+
| vend_id | prod_name    |
+---------+--------------+
|    1001 | .5 ton anvil |
|    1001 | 1 ton anvil  |
|    1001 | 2 ton anvil  |
+---------+--------------+


SELECT vend_id, prod_name
FROM products
WHERE vend_id <= 1002;

+---------+--------------+
| vend_id | prod_name    |
+---------+--------------+
|    1001 | .5 ton anvil |
|    1001 | 1 ton anvil  |
|    1001 | 2 ton anvil  |
|    1002 | Fuses        |
|    1002 | Oil can      |
+---------+--------------+

SELECT vend_id, prod_name
FROM products
WHERE vend_id != 1002;

+---------+----------------+
| vend_id | prod_name      |
+---------+----------------+
|    1001 | .5 ton anvil   |
|    1001 | 1 ton anvil    |
|    1001 | 2 ton anvil    |
|    1003 | Detonator      |
|    1003 | Bird seed      |
|    1003 | Carrots        |
|    1005 | JetPack 1000   |
|    1005 | JetPack 2000   |
|    1003 | Safe           |
|    1003 | Sling          |
|    1003 | TNT (1 stick)  |
|    1003 | TNT (5 sticks) |
+---------+----------------+


// 两者相同
SELECT prod_id, prod_name
FROM products
WHERE vend_id >= 1002 AND vend_id <= 1004;

SELECT vend_id, prod_name
FROM products
WHERE vend_id BETWEEN 1002 AND 1004;

+---------+----------------+
| vend_id | prod_name      |
+---------+----------------+
|    1003 | Detonator      |
|    1003 | Bird seed      |
|    1003 | Carrots        |
|    1002 | Fuses          |
|    1002 | Oil can        |
|    1003 | Safe           |
|    1003 | Sling          |
|    1003 | TNT (1 stick)  |
|    1003 | TNT (5 sticks) |
+---------+----------------+

SELECT cust_id, cust_email
FROM customers
WHERE cust_email IS NULL;

+---------+------------+
| cust_id | cust_email |
+---------+------------+
|   10002 | NULL       |
|   10005 | NULL       |
+---------+------------+

// 在通过过滤选择出不具有特定值的行时,不会返回NULL值。猜测:NULL只能被 IS NULL匹配到
SELECT cust_id, cust_email
FROM customers
WHERE cust_email != 'ylee@coyote.com';

+---------+---------------------+
| cust_id | cust_email          |
+---------+---------------------+
|   10003 | rabbit@wascally.com |
|   10004 | sam@yosemite.com    |
+---------+---------------------+

第7章 数据过滤

7.1 组合WHERE语句

用AND OR 进行组合,一下代码等价。

SELECT prod_id, prod_name
FROM products
WHERE vend_id >= 1002 AND vend_id <= 1004;

SELECT vend_id, prod_name
FROM products
WHERE vend_id BETWEEN 1002 AND 1004;

AND 的优先级高于 OR用()来进行组合运算

SELECT prod_name, prod_price
FROM products
WHERE vend_id = 1002 OR vend_id = 1003 AND prod_price >= 10;

+----------------+------------+
| prod_name      | prod_price |
+----------------+------------+
| Detonator      |      13.00 |
| Bird seed      |      10.00 |
| Fuses          |       3.42 |
| Oil can        |       8.99 |
| Safe           |      50.00 |
| TNT (5 sticks) |      10.00 |
+----------------+------------+


SELECT prod_name, prod_price
FROM products
WHERE (vend_id = 1002 OR vend_id = 1003) AND prod_price >= 10;

+----------------+------------+
| prod_name      | prod_price |
+----------------+------------+
| Detonator      |      13.00 |
| Bird seed      |      10.00 |
| Safe           |      50.00 |
| TNT (5 sticks) |      10.00 |
+----------------+------------+

猜测:AND操作可以把通过率低的条件放在前面,OR操作可以把通过率高的条件放在前面。这样可以减少运算次数,提高性能。

7.2 IN操作符

以下SQL语句等价

SELECT prod_name, prod_price, vend_id
FROM products
WHERE vend_id IN (1001, 1002, 1003)

SELECT prod_name, prod_price, vend_id
FROM products
WHERE vend_id = 1001 OR vend_id = 1002 OR vend_id = 1003;

7.3 NOT操作符

NOT对结果取反

一下SQL语句等价

SELECT prod_name, prod_price, vend_id
FROM products
WHERE NOT vend_id != 1001;

SELECT prod_name, prod_price, vend_id
FROM products
WHERE vend_id = 1001;

常用写法:找到不匹配项目

SELECT prod_name, prod_price, vend_id
FROM products
WHERE NOT vend_id IN(1001, 1002);

+----------------+------------+---------+
| prod_name      | prod_price | vend_id |
+----------------+------------+---------+
| Detonator      |      13.00 |    1003 |
| Bird seed      |      10.00 |    1003 |
| Carrots        |       2.50 |    1003 |
| JetPack 1000   |      35.00 |    1005 |
| JetPack 2000   |      55.00 |    1005 |
| Safe           |      50.00 |    1003 |
| Sling          |       4.49 |    1003 |
| TNT (1 stick)  |       2.50 |    1003 |
| TNT (5 sticks) |      10.00 |    1003 |
+----------------+------------+---------+

第8章 用通配符进行过滤

8.1 LIKE操作符

8.1.1 百分号(%)通配符

%能匹配任意数量的任意字符

%通配符不区分大小写,同时%不会匹配到NULL、

// 此时不区分大小写
SELECT prod_id, prod_name
FROM products
WHERE prod_name LIKE 'Jet%';

+---------+--------------+
| prod_id | prod_name    |
+---------+--------------+
| JP1000  | JetPack 1000 |
| JP2000  | JetPack 2000 |
+---------+--------------+



// 而=匹配是区分大小写的
SELECT prod_name
FROM products
WHERE prod_name = 'JERPACK 1000';

Empty set (0.00 sec)
8.1.2 下划线(_)通配符

_能匹配一个任意字符。

// _不能匹配到 .5 ton anvil
SELECT prod_name
FROM products
WHERE prod_name LIKE '_ ton anvil';

+-------------+
| prod_name   |
+-------------+
| 1 ton anvil |
| 2 ton anvil |
+-------------+

// %不能匹配到 .5 ton anvil
SELECT prod_name
FROM products
WHERE prod_name LIKE '% ton anvil';

+--------------+
| prod_name    |
+--------------+
| .5 ton anvil |
| 1 ton anvil  |
| 2 ton anvil  |
+--------------+

8.2 使用通配符的技巧

  1. 出于性能的考虑尽量少使用通配符
  2. 尽量把通配符的搜索靠后
  3. 注意通配符位置的争取性

第9章 用正则表达式进行搜索

9.2 使用MySQL正则表达式

9.2.1 基本字符匹配

正则是不是对内容进行全匹配的,只有内容中有一段值匹配即可

'.' 代表任意一个字符

正则默认不区分大小写,若需要可用BINARY关键字

SELECT prod_name
FROM products
WHERE prod_name REGEXP '000';

+--------------+
| prod_name    |
+--------------+
| JetPack 1000 |
| JetPack 2000 |
+--------------+

// '.' 代表任意一个字符 因此下面匹配的是长度至少为12的列
SELECT prod_name
FROM products
WHERE prod_name REGEXP '............';

+----------------+
| prod_name      |
+----------------+
| .5 ton anvil   |
| JetPack 1000   |
| JetPack 2000   |
| TNT (1 stick)  |
| TNT (5 sticks) |
+----------------+
9.2.2 进行OR匹配

'|' 表示或类似SELECT 中的OR语句

SELECT prod_name
FROM products
WHERE prod_name REGEXP '1000|2000'
ORDER BY prod_name;

+--------------+
| prod_name    |
+--------------+
| JetPack 1000 |
| JetPack 2000 |
+--------------+
9.2.3 匹配几个字符之一

'[x|y|z]'用[和]括起字符表示可以为x或y或z,代替全匹配的.

PS:[x|y|z]可以缩写为[xyz]

同时可以用来否定该集合(注意与定位符区分)

SELECT prod_name
FROM products
WHERE prod_name REGEXP '1|2 ton'
ORDER BY prod_name;

+---------------+
| prod_name     |
+---------------+
| 1 ton anvil   |
| 2 ton anvil   |
| JetPack 1000  |
| TNT (1 stick) |
+---------------+

SELECT prod_name
FROM products
WHERE prod_name REGEXP '[12] ton'
ORDER BY prod_name;

+-------------+
| prod_name   |
+-------------+
| 1 ton anvil |
| 2 ton anvil |
+-------------+

SELECT prod_name
FROM products
WHERE prod_name REGEXP '[^12] ton'
ORDER BY prod_name;

+--------------+
| prod_name    |
+--------------+
| .5 ton anvil |
+--------------+
9.2.4 匹配范围

[a-z]代表小写字母集合

猜测:拼接是从当前数据库编码表里的编码顺序去匹配的。

[z-a]会报错invalid character range

[a-Z]会报错invalid character range

[A-z]则会匹配[A-Z] | [[]^-`] | [a-z]

SELECT prod_name
FROM products
WHERE prod_name REGEXP BINARY '[A-z] anvil'
ORDER BY prod_name;

SELECT prod_name
FROM products
WHERE prod_name REGEXP BINARY '[A-Z] | [[]^-`] | [a-z] anvil'
ORDER BY prod_name;
9.2.5 匹配特殊字符

\\进行匹配

如果要匹配.应该要写\\.

同理如果想匹配\应该要写\\\

SELECT prod_name
FROM products
WHERE prod_name REGEXP BINARY '\\.';

+--------------+
| prod_name    |
+--------------+
| .5 ton anvil |
+--------------+
9.2.6 匹配字符表

感觉不实用

说明
[:alnum:] 任意字母和数字(同[a-zA-Z0-9])
[:alpha:] 任意字符(同[a-zA-Z])
[:blank:] 空格和制表(同[\t])
[:cntrl:] ASCII控制字符(ASCII 0到31和127)
[:digit:] 任意数字(同[0-9])
[:graph:] 与[:print:]相同,但不包括空格
[:lower:] 任意小写字母(同[a-z])
[:print:] 任意可打印字符
[:punct:] 既不在[:alnum:]又不在[:cntrl:]中的任意字符
[:space:] 包括空格在内的任意空白字符(同[\f\n\r\t\v])
[:upper:] 任意大写字母(同[A-Z])
[:xdigit:] 任意十六进制数字(同[a-fA-F0-9])
9.2.7 匹配多个实例
说明
* 0个或多个匹配
+ 1个或多个匹配(等于{1,})
? 0个或1个匹配(等于{0,1}) {n} 指定数目的匹配
{n,} 不少于指定数目的匹配
{n,m} 匹配数目的范围(m不超过255)

下述语句用? 修饰了s

SELECT prod_name
FROM products
WHERE prod_name REGEXP '\\([0-9] sticks?\\)';

+----------------+
| prod_name      |
+----------------+
| TNT (1 stick)  |
| TNT (5 sticks) |
+----------------+

匹配连在一起的4个数字

SELECT prod_name
FROM products
WHERE prod_name REGEXP '[0-9]{4}';

+--------------+
| prod_name    |
+--------------+
| JetPack 1000 |
| JetPack 2000 |
+--------------+
9.2.8 定位符
元字符 说明
^ 文本的开始
$ 文本的结尾
[[:<:]] 词的开始
[[:>:]] 词的结尾

检索所有以数字开头的产品名

SELECT prod_name
FROM products
WHERE prod_name REGEXP '[0-9.]';

+----------------+
| prod_name      |
+----------------+
| .5 ton anvil   |
| 1 ton anvil    |
| 2 ton anvil    |
| JetPack 1000   |
| JetPack 2000   |
| TNT (1 stick)  |
| TNT (5 sticks) |
+----------------+


SELECT prod_name
FROM products
WHERE prod_name REGEXP '^[0-9.]';

+--------------+
| prod_name    |
+--------------+
| .5 ton anvil |
| 1 ton anvil  |
| 2 ton anvil  |
+--------------+

第10章 创建计算字段

10.1 计算字段

有的数据不靠输入,而是靠其他数据计算出来的,我们可以用计算字段处理。

10.2 拼接字段

用Concat()函数进行拼接,以下语句把vendors中的vend_namevend_country进行拼接

SELECT Concat(vend_name, '(', vend_country, ')')
FROM vendors;

+-------------------------------------------+
| Concat(vend_name, '(', vend_country, ')') |
+-------------------------------------------+
| Anvils R Us(USA)                          |
| LT Supplies(USA)                          |
| ACME(USA)                                 |
| Furball Inc.(USA)                         |
| Jet Set(England)                          |
| Jouets Et Ours(France)                    |
+-------------------------------------------+

Trim(): 可以去除串左右的空格

RTrim(): 可以去除串右侧的空格

LTrim(): 可以去除串左侧的空格

使用方法如下

SELECT Concat(Trim(vend_name), '(', Trim(vend_country), ')')
FROM vendors;

别名:使用AS关键字赋予计算值别名

SELECT Concat(Trim(vend_name), '(', Trim(vend_country), ')') 
AS vend_title
FROM vendors;

+------------------------+
| vend_title             |
+------------------------+
| Anvils R Us(USA)       |
| LT Supplies(USA)       |
| ACME(USA)              |
| Furball Inc.(USA)      |
| Jet Set(England)       |
| Jouets Et Ours(France) |
+------------------------+

10.3 执行算术计算

SELECT prod_id, 
       quantity, 
       item_price, 
       quantity * item_price AS expanded_price
FROM orderitems
WHERE order_num = 20005;

+---------+----------+------------+----------------+
| prod_id | quantity | item_price | expanded_price |
+---------+----------+------------+----------------+
| ANV01   |       10 |       5.99 |          59.90 |
| ANV02   |        3 |       9.99 |          29.97 |
| TNT2    |        5 |      10.00 |          50.00 |
| FB      |        1 |      10.00 |          10.00 |
+---------+----------+------------+----------------+

第11章 使用数据处理函数

11.2.1 文本处理函数

SELECT vend_name, Upper(vend_name) AS vend_name_upcase
FROM vendors;

+----------------+------------------+
| vend_name      | vend_name_upcase |
+----------------+------------------+
| Anvils R Us    | ANVILS R US      |
| LT Supplies    | LT SUPPLIES      |
| ACME           | ACME             |
| Furball Inc.   | FURBALL INC.     |
| Jet Set        | JET SET          |
| Jouets Et Ours | JOUETS ET OURS   |
+----------------+------------------+

常用文本处理函数

函数 说明
Left() 返回串左边的字符
Length() 返回串的长度
Locate() 找出串的一个子串
Lower() 将串转换为小写
LTrim() 去掉串左边的空格
Right() 返回串右边的字符
RTrim() 去掉串右边的空格
Soundex() 返回串的SOUNDEX值
SubString() 返回子串的字符
Upper() 将串转换为大写

Soundex()能用来匹配相同发音的串

SELECT cust_name, cust_contact
FROM customers
WHERE Soundex(cust_contact) = Soundex('Y. Lie');

+-------------+--------------+
| cust_name   | cust_contact |
+-------------+--------------+
| Coyote Inc. | Y Lee        |
+-------------+--------------+
11.2.2 日期和时间处理函数

常用的日期和时间处理函数

函数 说明
AddDate() 增加一个日期(天、周等)
AddTime() 增加一个时间(时、分等)
CurDate() 返回当前日期
CurTime() 返回当前时间
Date() 返回日期时间的日期部分
DateDiff() 计算两个日期之差
Date_Add() 高度灵活的日期运算函数
Date_Format() 返回一个格式化的日期或时间串
Day() 返回一个日期的天数部分
DayOfWeek() 对于一个日期,返回对应的星期几
Hour() 返回一个时间的小时部分
Minute() 返回一个时间的分钟部分
Month() 返回一个日期的月份部分
Now() 返回当前日期和时间
Second() 返回一个时间的秒部分
Time() 返回一个日期时间的时间部分
Year() 返回一个日期的年份部分
// 选出所有 2005年9月份的订单
SELECT *
FROM orders
WHERE YEAR(order_date) = '2005' AND MONTH(order_date) = '09';
11.2.3 数值处理函数

常用数值处理函数

函数 说明
Abs() 返回一个数的绝对值
Cos() 返回一个角度的余弦
Exp() 返回一个数的指数值
Mod() 返回操作数的余数
Pi() 返回圆周率
Rand() 返回一个随机数
Sin() 返回一个角度的正弦
Sqrt() 返回一个数的平方根
Tan() 返回一个角度的正切

第12章 汇总数据

12.1 聚集函数

SQL聚集函数

函数 说明
AVG() 返回某列的平均值
COUNT() 返回某列的行数
MAX() 返回某列的最大值
MIN() 返回某列值之和
SUM() 返回某列值之和

AVG()

SELECT AVG(prod_price) AS avg_price
FROM products;

+-----------+
| avg_price |
+-----------+
| 16.133571 |
+-----------+

COUNT()

如果COUNT()指定列名若值为NULL的话会被忽略

SELECT COUNT(*) AS order_2005_09
FROM orders
WHERE YEAR(order_date) = '2005' AND MONTH(order_date) = '09';

+---------------+
| order_2005_09 |
+---------------+
|             3 |
+---------------+
12.1.3 MAX()函数
SELECT MAX(prod_price) AS max_price
FROM products;

+-----------+
| max_price |
+-----------+
|     55.00 |
+-----------+
12.1.4 MIN()函数
SELECT MIN(prod_price) AS min_price
FROM products;

+-----------+
| min_price |
+-----------+
|      2.50 |
+-----------+
12.1.5 SUM()函数
SELECT SUM(quantity * item_price) AS items_ordered
FROM orderitems
WHERE order_num = 20005;

+---------------+
| items_ordered |
+---------------+
|        149.87 |
+---------------+

12.2 聚焦不同值

DISTINCT关键字用于聚焦不同值,与之对应的是ALL关键字。ALL 关键字是默认的不需特殊指定。

// 无指定关键字
SELECT AVG(prod_price) AS avg_price
FROM products;

+-----------+
| avg_price |
+-----------+
| 16.133571 |
+-----------+

// 指定ALL关键字结果和无指定相同
SELECT AVG(ALL prod_price) AS avg_price
FROM products;

+-----------+
| avg_price |
+-----------+
| 16.133571 |
+-----------+

// DISTINCT 关键字只会统计不同值
SELECT AVG(DISTINCT prod_price) AS avg_price
FROM products;

+-----------+
| avg_price |
+-----------+
| 17.780833 |
+-----------+

12.3 组合聚集函数

SELECT COUNT(*) AS num_items,
       MIN(prod_price) AS price_min,
       MAX(prod_price) AS price_max,
       AVG(prod_price) AS price_avg
FROM products;

+-----------+-----------+-----------+-----------+
| num_items | price_min | price_max | price_avg |
+-----------+-----------+-----------+-----------+
|        14 |      2.50 |     55.00 | 16.133571 |
+-----------+-----------+-----------+-----------+

第13章 分组数据

13.2 创建分组

猜测执行顺序为:

  1. FROM products选择表
  2. GROUP BY vend_id把表分成4组
  3. 对每组进行SELECT vend_id, COUNT(*) AS num_prods操作
SELECT vend_id, COUNT(*) AS num_prods
FROM products
GROUP BY vend_id;

+---------+-----------+
| vend_id | num_prods |
+---------+-----------+
|    1001 |         3 |
|    1002 |         2 |
|    1003 |         7 |
|    1005 |         2 |
+---------+-----------+

// 使用 WITH ROLLUP 关键字可以再对分组结果进行汇总
SELECT vend_id, COUNT(*) AS num_prods
FROM products
GROUP BY vend_id WITH ROLLUP;

+---------+-----------+
| vend_id | num_prods |
+---------+-----------+
|    1001 |         3 |
|    1002 |         2 |
|    1003 |         7 |
|    1005 |         2 |
|    NULL |        14 |
+---------+-----------+

13.3 过滤分组

WHERE操作的对象是行,如要操作分组需要使用HAVING关键字

// 找出具有2个以上订单的客户
SELECT cust_id, COUNT(*) AS orders
FROM orders
GROUP BY cust_id
HAVING orders >= 2;

+---------+--------+
| cust_id | orders |
+---------+--------+
|   10001 |      2 |
+---------+--------+

// 找出至少有2件价格不低于10的产品的供应商
SELECT vend_id, COUNT(*) AS num_prods
FROM products
WHERE prod_price >= 10
GROUP BY vend_id
HAVING COUNT(*) >= 2;

+---------+-----------+
| vend_id | num_prods |
+---------+-----------+
|    1003 |         4 |
|    1005 |         2 |
+---------+-----------+

13.4 分组和排序

// 检索总计订单价格大于等于50的订 单的订单号和总计订单价格
SELECT order_num, SUM(quantity*item_price) AS ordertotal
FROM orderitems
GROUP BY order_num
HAVING SUM(quantity * item_price) >= 50;

+-----------+------------+
| order_num | ordertotal |
+-----------+------------+
|     20005 |     149.87 |
|     20006 |      55.00 |
|     20007 |    1000.00 |
|     20008 |     125.00 |
+-----------+------------+

// 进行排序
SELECT order_num, SUM(quantity*item_price) AS ordertotal
FROM orderitems
GROUP BY order_num
HAVING ordertotal >= 50
ORDER BY ordertotal;

+-----------+------------+
| order_num | ordertotal |
+-----------+------------+
|     20006 |      55.00 |
|     20008 |     125.00 |
|     20005 |     149.87 |
|     20007 |    1000.00 |
+-----------+------------+

13.5 SELECT子句顺序

子句 说明
SELECT 要返回的列或者表达式
FROM 从中检索数据的表
WHERE 行级过滤
GROUP BY 分组说明
HAVING 组级过滤
ORDER BY 输出排序顺序
LIMIT 要检索的行数

第14章 使用子查询

要查询所有购买过TNT2的用户的信息

  1. 检索包含物品TNT2的所有订单的编号。
  2. 检索具有前一步骤列出的订单编号的所有客户的ID。
  3. 检索前一步骤返回的所有客户ID的客户信息。
SELECT order_num 
FROM orderitems
WHERE prod_id = 'TNT2';

+-----------+
| order_num |
+-----------+
|     20005 |
|     20007 |
+-----------+

SELECT cust_id 
FROM orders
WHERE order_num IN (20005, 20007);

+---------+
| cust_id |
+---------+
|   10001 |
|   10004 |
+---------+


SELECT cust_id, cust_name
FROM customers
WHERE cust_id IN (10001, 10004);

+---------+----------------+
| cust_id | cust_name      |
+---------+----------------+
|   10001 | Coyote Inc.    |
|   10004 | Yosemite Place |
+---------+----------------+

拼接写法

SELECT cust_id, cust_name
FROM customers
WHERE cust_id IN (SELECT cust_id 
                  FROM orders 
                  WHERE order_num IN (SELECT order_num
                                      FROM orderitems
                                      WHERE prod_id = 'TNT2'));
                                      
+---------+----------------+
| cust_id | cust_name      |
+---------+----------------+
|   10001 | Coyote Inc.    |
|   10004 | Yosemite Place |
+---------+----------------+

计算每个客户的订单数目

SELECT cust_id, 
       cust_name,
       (SELECT COUNT(*)
        FROM orders
        WHERE orders.cust_id = customers.cust_id) AS orders
FROM customers
ORDER BY cust_id;

+---------+----------------+--------+
| cust_id | cust_name      | orders |
+---------+----------------+--------+
|   10001 | Coyote Inc.    |      2 |
|   10002 | Mouse House    |      0 |
|   10003 | Wascals        |      1 |
|   10004 | Yosemite Place |      1 |
|   10005 | E Fudd         |      1 |
+---------+----------------+--------+

WHERE orders.cust_id = customers.cust_id
可改为
WHERE cust_id = customers.cust_id
结果相同
表名的获取遵从就近原则

第15章 联结表

15.2 创建联结

// 找出所有的产品并标注出他们的生产商
SELECT   vend_name, prod_name, prod_price
FROM     vendors, products
WHERE    vendors.vend_id = products.vend_id // 当出现二异性时,必须使用完整列名
ORDER BY vend_name, prod_name;

+-------------+----------------+------------+
| vend_name   | prod_name      | prod_price |
+-------------+----------------+------------+
| ACME        | Bird seed      |      10.00 |
| ACME        | Carrots        |       2.50 |
| ACME        | Detonator      |      13.00 |
| ACME        | Safe           |      50.00 |
| ACME        | Sling          |       4.49 |
| ACME        | TNT (1 stick)  |       2.50 |
| ACME        | TNT (5 sticks) |      10.00 |
| Anvils R Us | .5 ton anvil   |       5.99 |
| Anvils R Us | 1 ton anvil    |       9.99 |
| Anvils R Us | 2 ton anvil    |      14.99 |
| Jet Set     | JetPack 1000   |      35.00 |
| Jet Set     | JetPack 2000   |      55.00 |
| LT Supplies | Fuses          |       3.42 |
| LT Supplies | Oil can        |       8.99 |
+-------------+----------------+------------+

猜测:如果FROM存在多张表就是对多张表的笛卡尔积进行查询。若vendors表中出现因为输入错误造成id重复的话则上述结果会出现同一件产品出现2次的情况。

进行如下测试

// 这样写会报错因为vend_id存在二义性
SELECT   vend_name, prod_name, prod_name, vend_id
FROM     vendors, products
ORDER BY vend_name, prod_name;

// 输出笛卡尔积
SELECT   vend_name, prod_name, prod_name
FROM     vendors, products
ORDER BY vend_name, prod_name;
+----------------+----------------+----------------+
| vend_name      | prod_name      | prod_name      |
+----------------+----------------+----------------+
| ACME           | .5 ton anvil   | .5 ton anvil   |
| ACME           | 1 ton anvil    | 1 ton anvil    |
| ACME           | 2 ton anvil    | 2 ton anvil    |
| ACME           | Bird seed      | Bird seed      |
| ACME           | Carrots        | Carrots        |
| ACME           | Detonator      | Detonator      |
| ACME           | Fuses          | Fuses          |
| ACME           | JetPack 1000   | JetPack 1000   |
| ACME           | JetPack 2000   | JetPack 2000   |
| ACME           | Oil can        | Oil can        |
| ACME           | Safe           | Safe           |
| ACME           | Sling          | Sling          |
| ACME           | TNT (1 stick)  | TNT (1 stick)  |
| ACME           | TNT (5 sticks) | TNT (5 sticks) |
| Anvils R Us    | .5 ton anvil   | .5 ton anvil   |
| Anvils R Us    | 1 ton anvil    | 1 ton anvil    |
| Anvils R Us    | 2 ton anvil    | 2 ton anvil    |
| Anvils R Us    | Bird seed      | Bird seed      |
| Anvils R Us    | Carrots        | Carrots        |
| Anvils R Us    | Detonator      | Detonator      |
| Anvils R Us    | Fuses          | Fuses          |
| Anvils R Us    | JetPack 1000   | JetPack 1000   |
| Anvils R Us    | JetPack 2000   | JetPack 2000   |
| Anvils R Us    | Oil can        | Oil can        |
| Anvils R Us    | Safe           | Safe           |
| Anvils R Us    | Sling          | Sling          |
| Anvils R Us    | TNT (1 stick)  | TNT (1 stick)  |
| Anvils R Us    | TNT (5 sticks) | TNT (5 sticks) |
| Furball Inc.   | .5 ton anvil   | .5 ton anvil   |
| Furball Inc.   | 1 ton anvil    | 1 ton anvil    |
| Furball Inc.   | 2 ton anvil    | 2 ton anvil    |
| Furball Inc.   | Bird seed      | Bird seed      |
| Furball Inc.   | Carrots        | Carrots        |
| Furball Inc.   | Detonator      | Detonator      |
| Furball Inc.   | Fuses          | Fuses          |
| Furball Inc.   | JetPack 1000   | JetPack 1000   |
| Furball Inc.   | JetPack 2000   | JetPack 2000   |
| Furball Inc.   | Oil can        | Oil can        |
| Furball Inc.   | Safe           | Safe           |
| Furball Inc.   | Sling          | Sling          |
| Furball Inc.   | TNT (1 stick)  | TNT (1 stick)  |
| Furball Inc.   | TNT (5 sticks) | TNT (5 sticks) |
| Jet Set        | .5 ton anvil   | .5 ton anvil   |
| Jet Set        | 1 ton anvil    | 1 ton anvil    |
| Jet Set        | 2 ton anvil    | 2 ton anvil    |
| Jet Set        | Bird seed      | Bird seed      |
| Jet Set        | Carrots        | Carrots        |
| Jet Set        | Detonator      | Detonator      |
| Jet Set        | Fuses          | Fuses          |
| Jet Set        | JetPack 1000   | JetPack 1000   |
| Jet Set        | JetPack 2000   | JetPack 2000   |
| Jet Set        | Oil can        | Oil can        |
| Jet Set        | Safe           | Safe           |
| Jet Set        | Sling          | Sling          |
| Jet Set        | TNT (1 stick)  | TNT (1 stick)  |
| Jet Set        | TNT (5 sticks) | TNT (5 sticks) |
| Jouets Et Ours | .5 ton anvil   | .5 ton anvil   |
| Jouets Et Ours | 1 ton anvil    | 1 ton anvil    |
| Jouets Et Ours | 2 ton anvil    | 2 ton anvil    |
| Jouets Et Ours | Bird seed      | Bird seed      |
| Jouets Et Ours | Carrots        | Carrots        |
| Jouets Et Ours | Detonator      | Detonator      |
| Jouets Et Ours | Fuses          | Fuses          |
| Jouets Et Ours | JetPack 1000   | JetPack 1000   |
| Jouets Et Ours | JetPack 2000   | JetPack 2000   |
| Jouets Et Ours | Oil can        | Oil can        |
| Jouets Et Ours | Safe           | Safe           |
| Jouets Et Ours | Sling          | Sling          |
| Jouets Et Ours | TNT (1 stick)  | TNT (1 stick)  |
| Jouets Et Ours | TNT (5 sticks) | TNT (5 sticks) |
| LT Supplies    | .5 ton anvil   | .5 ton anvil   |
| LT Supplies    | 1 ton anvil    | 1 ton anvil    |
| LT Supplies    | 2 ton anvil    | 2 ton anvil    |
| LT Supplies    | Bird seed      | Bird seed      |
| LT Supplies    | Carrots        | Carrots        |
| LT Supplies    | Detonator      | Detonator      |
| LT Supplies    | Fuses          | Fuses          |
| LT Supplies    | JetPack 1000   | JetPack 1000   |
| LT Supplies    | JetPack 2000   | JetPack 2000   |
| LT Supplies    | Oil can        | Oil can        |
| LT Supplies    | Safe           | Safe           |
| LT Supplies    | Sling          | Sling          |
| LT Supplies    | TNT (1 stick)  | TNT (1 stick)  |
| LT Supplies    | TNT (5 sticks) | TNT (5 sticks) |
+----------------+----------------+----------------+
15.2.2 内部联结

使用 INNER JOINON组成内部联结。这种写法,此种写法与WHERE一致

SELECT vend_name, prod_name, prod_price
FROM vendors INNER JOIN products
ON vendors.vend_id = products.vend_id;

+-------------+----------------+------------+
| vend_name   | prod_name      | prod_price |
+-------------+----------------+------------+
| Anvils R Us | .5 ton anvil   |       5.99 |
| Anvils R Us | 1 ton anvil    |       9.99 |
| Anvils R Us | 2 ton anvil    |      14.99 |
| LT Supplies | Fuses          |       3.42 |
| LT Supplies | Oil can        |       8.99 |
| ACME        | Detonator      |      13.00 |
| ACME        | Bird seed      |      10.00 |
| ACME        | Carrots        |       2.50 |
| ACME        | Safe           |      50.00 |
| ACME        | Sling          |       4.49 |
| ACME        | TNT (1 stick)  |       2.50 |
| ACME        | TNT (5 sticks) |      10.00 |
| Jet Set     | JetPack 1000   |      35.00 |
| Jet Set     | JetPack 2000   |      55.00 |
+-------------+----------------+------------+
15.2.3 联结多个表
// 查找订单20005里面的商品和其供应商的信息。
SELECT order_num, prod_name, vend_name, prod_price, quantity
FROM orderitems, products, vendors
WHERE products.vend_id = vendors.vend_id
      AND orderitems.prod_id = products.prod_id
      AND order_num = 20005;
      
+-----------+----------------+-------------+------------+----------+
| order_num | prod_name      | vend_name   | prod_price | quantity |
+-----------+----------------+-------------+------------+----------+
|     20005 | .5 ton anvil   | Anvils R Us |       5.99 |       10 |
|     20005 | 1 ton anvil    | Anvils R Us |       9.99 |        3 |
|     20005 | TNT (5 sticks) | ACME        |      10.00 |        5 |
|     20005 | Bird seed      | ACME        |      10.00 |        1 |
+-----------+----------------+-------------+------------+----------+

第16章 创建高级联结

16.1 使用表别名

1.可以缩短sql语句

SELECT cust_name, cust_contact
FROM customers AS c, orders AS o, orderitems AS oi
WHERE c.cust_id = o.cust_id
            AND oi.order_num = o.order_num
            AND prod_id = 'TNT2';

2.可以对同一张表引用多次(在products表中查询出‘DTNTR’的生产商的所有产品)

// 不使用表别名
SELECT prod_id, prod_name, vend_id
FROM products
WHERE vend_id = (SELECT vend_id
                 FROM products
                 WHERE prod_id = 'DTNTR')
                 
// 使用表别名
SELECT p1.prod_id, p1.prod_name, p1.vend_id
FROM products as p1, products as p2
WHERE p1.vend_id = p2.vend_id
AND p2.prod_id = 'DTNTR'

+---------+----------------+---------+
| prod_id | prod_name      | vend_id |
+---------+----------------+---------+
| DTNTR   | Detonator      |    1003 |
| FB      | Bird seed      |    1003 |
| FC      | Carrots        |    1003 |
| SAFE    | Safe           |    1003 |
| SLING   | Sling          |    1003 |
| TNT1    | TNT (1 stick)  |    1003 |
| TNT2    | TNT (5 sticks) |    1003 |
+---------+----------------+---------+

16.2 使用不同类型的联结

16.2.1 自联结
// 找出和DTNTR相同生产商的产品
SELECT p1.prod_id, p1.prod_name
FROM products AS p1, products AS p2
WHERE p1.vend_id = p2.vend_id
      AND p2.prod_id = 'DTNTR';
            
+---------+----------------+
| prod_id | prod_name      |
+---------+----------------+
| DTNTR   | Detonator      |
| FB      | Bird seed      |
| FC      | Carrots        |
| SAFE    | Safe           |
| SLING   | Sling          |
| TNT1    | TNT (1 stick)  |
| TNT2    | TNT (5 sticks) |
+---------+----------------+
16.2.3 外部联结

关于内部联结与外部联结的区别

内部联结 = A ∩ B

外部联结 = X ∪ (A ∩ B) = X X为被LEFT 或 RIGHT 标记的表

SELECT customers.cust_id, orders.order_num
FROM customers LEFT OUTER JOIN orders
ON customers.cust_id = orders.cust_id;

+---------+-----------+
| cust_id | order_num |
+---------+-----------+
|   10001 |     20005 |
|   10001 |     20009 |
|   10002 |      NULL |
|   10003 |     20006 |
|   10004 |     20007 |
|   10005 |     20008 |
+---------+-----------+

SELECT customers.cust_id, orders.order_num
FROM customers RIGHT OUTER JOIN orders
ON customers.cust_id = orders.cust_id;

+---------+-----------+
| cust_id | order_num |
+---------+-----------+
|   10001 |     20005 |
|   10001 |     20009 |
|   10003 |     20006 |
|   10004 |     20007 |
|   10005 |     20008 |
+---------+-----------+

SELECT customers.cust_id, orders.order_num
FROM customers INNER JOIN orders
ON customers.cust_id = orders.cust_id;

+---------+-----------+
| cust_id | order_num |
+---------+-----------+
|   10001 |     20005 |
|   10001 |     20009 |
|   10003 |     20006 |
|   10004 |     20007 |
|   10005 |     20008 |
+---------+-----------+
16.3 使用待聚集函数的联结
// 计算所有已购买过产品的用户的 购买量
SELECT customers.cust_name,
       customers.cust_id,
       COUNT(orders.order_num) AS num_ord
FROM customers INNER JOIN orders
ON customers.cust_id = orders.cust_id
GROUP BY customers.cust_id;

+----------------+---------+---------+
| cust_name      | cust_id | num_ord |
+----------------+---------+---------+
| Coyote Inc.    |   10001 |       2 |
| Wascals        |   10003 |       1 |
| Yosemite Place |   10004 |       1 |
| E Fudd         |   10005 |       1 |
+----------------+---------+---------+

// 计算所有用户的购买量
SELECT customers.cust_name,
       customers.cust_id,
       COUNT(orders.order_num) AS num_ord
FROM customers LEFT OUTER JOIN orders
ON customers.cust_id = orders.cust_id
GROUP BY customers.cust_id;

+----------------+---------+---------+
| cust_name      | cust_id | num_ord |
+----------------+---------+---------+
| Coyote Inc.    |   10001 |       2 |
| Mouse House    |   10002 |       0 |
| Wascals        |   10003 |       1 |
| Yosemite Place |   10004 |       1 |
| E Fudd         |   10005 |       1 |
+----------------+---------+---------+

第17章 组合查询

17.1 组合查询

组合查询用以返回多种匹配结果的并集

17.2 创建组合查询

17.2.1 使用UNION
// 查找出价格小于等于5,以及供应商为1001和1002的所有物品
SELECT vend_id, prod_id, prod_price
FROM products
WHERE prod_price <= 5
UNION 
SELECT vend_id, prod_id, prod_price
FROM products
WHERE vend_id IN(1001, 1002);

// 结果同上
SELECT vend_id, prod_id, prod_price
FROM products
WHERE prod_price <= 5 OR vend_id IN(1001, 1002);

+---------+---------+------------+
| vend_id | prod_id | prod_price |
+---------+---------+------------+
|    1003 | FC      |       2.50 |
|    1002 | FU1     |       3.42 |
|    1003 | SLING   |       4.49 |
|    1003 | TNT1    |       2.50 |
|    1001 | ANV01   |       5.99 |
|    1001 | ANV02   |       9.99 |
|    1001 | ANV03   |      14.99 |
|    1002 | OL1     |       8.99 |
+---------+---------+------------+
17.2.2 UNION规则
  1. UNION用来分割SELECT语句

  2. 每个查询必须包含相同的列、表达式或聚集函数

  3. 列数据类型必须兼容:类型不必完全相同,但必须是DBMS可以

    隐含地转换的类型(例如,不同的数值类型或不同的日期类型)

17.2.3 包含或取消重复的行

如果多个SELECT匹配到了同一行,UNION默认会去除重复行。

如果允许重复出现则用UNION ALL代替UNION

SELECT vend_id, prod_id, prod_price
FROM products
WHERE prod_price <= 5
UNION 
SELECT vend_id, prod_id, prod_price
FROM products
WHERE vend_id IN(1001, 1002);

+---------+---------+------------+
| vend_id | prod_id | prod_price |
+---------+---------+------------+
|    1003 | FC      |       2.50 |
|    1002 | FU1     |       3.42 |
|    1003 | SLING   |       4.49 |
|    1003 | TNT1    |       2.50 |
|    1001 | ANV01   |       5.99 |
|    1001 | ANV02   |       9.99 |
|    1001 | ANV03   |      14.99 |
|    1002 | FU1     |       3.42 |
|    1002 | OL1     |       8.99 |
+---------+---------+------------+
17.2.4 对组合查询结果排序

排序语句出现在最后一条SELECT语句之后

SELECT vend_id, prod_id, prod_price
FROM products
WHERE prod_price <= 5
UNION 
SELECT vend_id, prod_id, prod_price
FROM products
WHERE vend_id IN(1001, 1002)
ORDER BY vend_id;

+---------+---------+------------+
| vend_id | prod_id | prod_price |
+---------+---------+------------+
|    1001 | ANV01   |       5.99 |
|    1001 | ANV02   |       9.99 |
|    1001 | ANV03   |      14.99 |
|    1002 | FU1     |       3.42 |
|    1002 | OL1     |       8.99 |
|    1003 | FC      |       2.50 |
|    1003 | SLING   |       4.49 |
|    1003 | TNT1    |       2.50 |
+---------+---------+------------+

第18章 全文本搜索

18.2.2 进行全文本搜索
// 两种语句效果相同

SELECT note_text
FROM productnotes
WHERE MATCH(note_text) Against('rabbit');

SELECT note_text
FROM productnotes
WHERE note_text LIKE '%rabbit%';
18.2.3 使用查询扩展

在使用文本搜索查询到结果之后,在用结果内的词进行查询

SELECT note_text
FROM productnotes
WHERE MATCH(note_text) AGAINST('anvils' WITH QUERY EXPANSION);

Multiple customer returns, anvils failing to drop fast enough or falling backwards on purchaser. Recommend that customer considers using heavier anvils.

Customer complaint:Sticks not individually wrapped, too easy to mistakenly detonate all at once.Recommend individual wrapping.Customer complaint:Not heavy enough to generate flying stars around head of victim. If being purchased for dropping, recommend ANV02 or ANV03 instead.
Please note that no returns will be accepted if safe opened using explosives.
Customer complaint: rabbit has been able to detect trap, food apparently less effective now.

Customer complaint:Circular hole in safe floor can apparently be easily cut with handsaw.Matches not included, recommend purchase of matches or detonator (item DTNTR).
18.2.4 布尔文本搜索

MySQL支持全文本搜索的另外一种形式,称为布尔方式(boolean

mode)。以布尔方式,可以提供关于如下内容的细节:

  1. 要匹配的词;
  2. 要排斥的词(如果某行包含这个词,则不返回该行,即使它包含其他指定的词也是如此);
  3. 排列提示(指定某些词比其他词更重要,更重要的词等级更高);
  4. 表达式分组;
  5. 另外一些内容。
// 匹配包含'heavy'的行
SELECT onte_text
FROM productnotes
WHERE Match(note_text) Against('heavy' IN BOOLEN MODE);

Item is extremely heavy. Designed for dropping, not recommended for use with slings, ropes, pulleys, or tightropes.

Customer complaint:
Not heavy enough to generate flying stars around head of victim. If being purchased for dropping, recommend ANV02 or ANV03 instead.

// 匹配包含'heavy'且不包含'rope*'的行
SELECT note_text
FROM productnotes
WHERE MATCH(note_text) Against('heavy -rope*' IN BOOLEAN MODE);

Customer complaint:
Not heavy enough to generate flying stars around head of victim. If being purchased for dropping, recommend ANV02 or ANV03 instead.

全文本布尔操作符

布尔操作符 说明
N/A(无符号) 包含,词必须存在
+ 包含,词必须存在
- 排除,次必须不出现
> 包含,且增加等级值
< 包含,且减少等级值
() 把词组成表达式
~ 取消一个词的排序值
* 词尾通配符
"" 定义一个短语

举例操作

// 搜索包含rabbit 和 bait的行
SELECT note_text
FROM productnotes
WHERE MATCH(note_text) Against('+rabbit +bait' IN BOOLEAN MODE);

// 搜索包含rabbit和bait中至少一个的行
SELECT note_text
FROM productnotes
WHERE MATCH(note_text) Against('rabbit bait' IN BOOLEAN MODE);

// 搜索包含rabbit bait的行
SELECT note_text
FROM productnotes
WHERE MATCH(note_text) Against('"rabbit bait"' IN BOOLEAN MODE);

// 匹配rabbit和carrot,增加前者等级,降低后者等级
SELECT note_text
FROM productnotes
WHERE MATCH(note_text) Against('>rabbit <carrot' IN BOOLEAN MODE);

// 搜索safe和combination,降低后者等级
SELECT note_text
FROM productnotes
WHERE MATCH(note_text) Against('+safe +(<combination)' IN BOOLEAN MODE);
18.2.5 全文本搜索的使用说明
  • 在索引全文本数据时,短词被忽略且从索引中排除。短词定义为 那些具有3个或3个以下字符的词(如果需要,这个数目可以更改)。
  • MySQL带有一个内建的非用词(stopword)列表,这些词在索引 全文本数据时总是被忽略。如果需要,可以覆盖这个列表(请参阅MySQL文档以了解如何完成此工作)。
  • 许多词出现的频率很高,搜索它们没有用处(返回太多的结果)。 因此,MySQL规定了一条50%规则,如果一个词出现在50%以上 的行中,则将它作为一个非用词忽略。50%规则不用于IN BOOLEAN MODE。
  • 如果表中的行数少于3行,则全文本搜索不返回结果(因为每个词 或者不出现,或者至少出现在50%的行中)。
  • 忽略词中的单引号。例如,don't索引为dont。
  • 不具有词分隔符(包括日语和汉语)的语言不能恰当地返回全文本搜索结果。
  • 如前所述,仅在MyISAM数据库引擎中支持全文本搜索。

第19章 插入数据

19.1 数据插入

使用INSERT插入(或添加)行到数据库表中。有以下几种插入方式。

  • 插入完整行
  • 插入行的一部分
  • 插入多行
  • 插入某些查询的结果

19.2 插入完整的行

key和nullable==False的Column可以省略

// 不安全的写法(严重依赖Column的顺序)
INSERT INTO Customers
VALUES(NULL, 
       'Pep E. LaPew',
       '100 Main Street', 
       'Log Angeles', 
       'CA', 
       '90046', 
       'USA', 
       NULL, 
       NULL)
       
// 更安全的写法,同时更繁琐的写法
INSERT INTO customers(cust_name, 
                      cust_address, 
                      cust_city, 
                      cust_state, 
                      cust_zip, 
                      cust_country, 
                      cust_contact, 
                      cust_email)
VALUES('Pep E. LaPew',
       '100 Main Street', 
       'Log Angeles', 
       'CA', 
       '90046', 
       'USA', 
       NULL, 
       NULL)

19.3 插入多个行

INSERT INTO customers(cust_name, 
                      cust_address, 
                      cust_city, 
                      cust_state, 
                      cust_zip, 
                      cust_country)
VALUES('Pep E. LaPew',
       '100 Main Street', 
       'Log Angeles', 
       'CA', 
       '90046', 
       'USA'),
      ('M. Martian', 
       '42 Galaxy Way', 
       'New York', 
       'NY', 
       '11213', 
       'USA');

19.4 插入检索出的数据

INSERT INTO customers(cust_id, 
                      cust_contact, 
                      cust_email, 
                      cust_name, 
                      cust_address, 
                      cust_city, 
                      cust_state, 
                      cust_zip, 
                      cust_country)
SELECT cust_id, 
       cust_contact, 
       cust_email, 
       cust_name, 
       cust_address, 
       cust_city, 
       cust_state, 
       cust_zip, 
       cust_country
FROM custnew;

第20章 更新和删除数据

20.1 更新数据

为了更新(修改)表中的数据,可使用UPDATE语句。可采用两种方 式使用UPDATE:

  • 更新表中特定行
  • 更新表中所有行。
// 更新单列
UPDATE customers
SET cust_email = 'elmer@fudd.com'
WHERE cust_id = 10005;

// 更新多列
UPDATE customers
SET cust_name = 'The Fudds',
    cust_email = 'elmer@fudd.com'
WHERE cust_id = 10005;

20.2 删除数据

为了从一个表中删除(去掉)数据,使用DELETE语句。可以两种方 式使用DELETE:

  • 从表中删除特定的行;
  • 从表中删除所有行。
DELETE FROM customers
WHERE cust_id = 10006;

第21章 创建和操纵表

21.1 创建表

MySQL不仅用于表数据操纵,而且还可以用来执行数据库和表的所 有操作,包括表本身的创建和处理。 一般有两种创建表的方法:

  • 使用具有交互式创建和管理表的工具(如第2章讨论的工具);
  • 表也可以直接用MySQL语句操纵。
21.1.1 表创建基础

为利用CREATE TABLE创建表,必须给出下列信息:

  • 新表的名字,在关键字CREATE TABLE之后给出;
  • 表列的名字和定义,用逗号分隔。
CREATE TABLE custnew(
cust_id         int         NOT NULL AUTO_INCREMENT,
cust_name       char(50)    NOT NULL,
cust_address    char(50)    NULL,
cust_city       char(50)    NULL,
cust_state      char(5)     NULL,
cust_zip        char(10)    NULL,
cust_country    char(50)    NULL,
cust_email      char(50)    NULL,
PRIMARY KEY (cust_id)
)ENGINE=InnoDB;
21.1.3 主键再介绍

主键可以是多个Colomn的组合

CREATE TABLE ordernew
(
    order_num       int         NOT NULL,
    order_item      int         NOT NULL,
    prod_id         char(10)    NOT NULL,
    quantity        int         NOT NULL,
    item_price decimal(8,2)     NOT NULL,
    PRIMARY KEY (order_num, order_item)
)ENGINE=INNODB
21.1.4 使用AUTO_INCREMENT

一般用来实现主键自增

21.1.5 指定默认值

DEFAULT

CREATE TABLE ordernew
(
    order_num       int         NOT NULL,
    order_item      int         NOT NULL,
    prod_id         char(10)    NOT NULL,
    quantity        int         NOT NULL DEFAULT 1,
    item_price decimal(8,2)     NOT NULL,
    PRIMARY KEY (order_num, order_item)
)ENGINE=INNODB
21.1.6 引擎类型

以下是几个需要知道的引擎:

  • InnoDB是一个可靠的事务处理引擎,它不支持全文本搜索;
  • MEMORY在功能等同于MyISAM,但由于数据存储在内存(不是磁盘) 中,速度很快(特别适合于临时表);
  • MyISAM是一个性能极高的引擎,它支持全文本搜索(参见第18章), 但不支持事务处理。

21.2 更新表

ALTER TABLE关键字用来更新表

// 增加vend_phone列
ALTER TABLE vendors
ADD vend_phone CHAR(20);

// 删除vend_phone列
ALTER TABLE vendors
DROP COLUMN vend_phone

21.3 删除表

// 删除整张表
DROP TABLE customer;

21.4 重命名表

RENAME TABLE customers TO backup_customers;

第22章 使用视图

22.1 视图

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

可以把查询结果包装成一个视图,然后对视图进行表操作.

22.2 使用视图

  • 视图用CREATE VIEW语句来创建。
  • 使用SHOW CREATE VIEW viewname;来查看创建视图的语句。
  • 用DROP删除视图,其语法为DROP VIEW viewname;。
  • 更新视图时,可以先用DROP再用CREATE,也可以直接用CREATE OR REPLACE VIEW。如果要更新的视图不存在,则第2条更新语句会创 建一个视图;如果要更新的视图存在,则第2条更新语句会替换原 有视图。
22.2.1 使用视图简化复杂的联结
// 创建productcustomers表
CREATE VIEW productcustomers AS
SELECT cust_name, cust_contact, prod_id
FROM customers, orders, orderitems
WHERE customers.cust_id = orders.cust_id
AND orderitems.order_num = orders.order_num;

// 从productcustomers表中查询数据
SELECT cust_name, cust_contact
FROM productcustomers
WHERE prod_id = 'TNT2';
22.2.2 用视图重新格式化检索出的数据
// 原始代码
SELECT CONCAT(RTRIM(vend_name),'(',RTRIM(vend_country), ')') AS vend_title
FROM vendors
ORDER BY vend_name;

// 使用视图代替
CREATE VIEW vendorlocations AS
SELECT CONCAT(RTRIM(vend_name),'(',RTRIM(vend_country), ')') AS vend_title
FROM vendors
ORDER BY vend_name;

SELECT *
FROM vendorlocations;

+------------------------+
| vend_title             |
+------------------------+
| ACME(USA)              |
| Anvils R Us(USA)       |
| Furball Inc.(USA)      |
| Jet Set(England)       |
| Jouets Et Ours(France) |
| LT Supplies(USA)       |
+------------------------+
22.2.3 用视图过滤不想要的数据
CREATE VIEW customermaillist AS 
SELECT cust_id, cust_name, cust_email
FROM customers
WHERE cust_email IS NOT NULL;

SELECT *
FROM customermaillist;
22.2.4 使用视图与计算字段
CREATE VIEW orderitemsexpanded AS
SELECT order_num,
       prod_id,
       quantity,
       item_price,
       quantity*item_price AS expanded_price
FROM orderitems;

SELECT *
FROM orderitemsexpanded
WHERE order_num = 20005;

+-----------+---------+----------+------------+----------------+
| order_num | prod_id | quantity | item_price | expanded_price |
+-----------+---------+----------+------------+----------------+
|     20005 | ANV01   |       10 |       5.99 |          59.90 |
|     20005 | ANV02   |        3 |       9.99 |          29.97 |
|     20005 | TNT2    |        5 |      10.00 |          50.00 |
|     20005 | FB      |        1 |      10.00 |          10.00 |
+-----------+---------+----------+------------+----------------+

第23章 使用存储过程

23.3.2 创建存储过程
CREATE PROCEDURE productpricing()
BEGIN
    SELECT Avg(prod_price) AS priceaverage
    FROM products;
END;

CALL productpricing();

+--------------+
| priceaverage |
+--------------+
|    16.133571 |
+--------------+
23.3.3 删除存储过程
DROP PROCEDURE productpricing;
23.3.4 使用参数

OUT类似引用传递

IN类似值传递

/** 获取产品的最低价,最高价,和平均价 **/

CREATE PROCEDURE productpricing1(
    OUT pl DECIMAL(8,2),
    OUT ph DECIMAL(8,2),
    OUT pa DECIMAL(8,2)
)
BEGIN
    SELECT MIN(prod_price)
    INTO pl
    FROM products;
    SELECT MAX(prod_price)
    INTO ph
    FROM products;
    SELECT AVG(prod_price)
    INTO pa
    FROM products;
END;



CALL productpricing1(@pricelow, @pricehigh, @priceaverage)


SELECT @pricelow;               // 2.50
SELECT @pricehigh;              // 55.00
SELECT @priceaverage;           // 16.13

SELECT @pricelow, @pricehigh, @priceaverage;
+-----------+------------+---------------+
| @pricelow | @pricehigh | @priceaverage |
+-----------+------------+---------------+
|      2.50 |      55.00 |         16.13 |
+-----------+------------+---------------+


/** 计算某个订单的总价 **/
CREATE PROCEDURE ordertotal(
    IN onumber INT,
    OUT ototal DECIMAL(8,2)
)
BEGIN
    SELECT SUM(item_price*quantity)
    FROM orderitems
    WHERE order_num = onumber
    INTO ototal;
END;



CALL ordertotal(20005, @total);

SELECT @total;

+--------+
| @total |
+--------+
| 149.87 |
+--------+
23.3.5 建立智能存储过程

即逻辑判断

CREATE PROCEDURE ordertotal(
    IN onumber INT,
    IN taxable BOOLEAN,
    OUT ototal DECIMAL(8,2)
)

BEGIN 
    DECLARE total DECIMAL(8,2);
    DECLARE taxrate INT DEFAULT 6;
    
    SELECT SUM(item_price * quantity)
    FROM orderitems
    WHERE order_num = onumber
    INTO total;
    
    IF taxable THEN
        SELECT total+(total/100*taxrate) INTO total;
    END IF;
    
    SELECT total INTO ototal;
    
END
    

CALL ordertotal(20005, 0, @total);
SELECT @total;
+--------+
| @total |
+--------+
| 149.87 |
+--------+

CALL ordertotal(20005, 1, @total);
SELECT @total;
+--------+
| @total |
+--------+
| 158.86 |
+--------+

第24章 使用游标

24.1 游标

用来对SELECT结果进行分页

24.2 使用游标

DECLARE命名游标

OPEN打开游标

COLSE关闭游标

FETCH用游标检索数据

第25章 使用触发器

25.1 触发器

可以给表添加触发器,在DELETE,INSERT,UPDATE语句执行时触发某些操作.

第26张 管理事务处理

26.1 事务处理

在使用事务和事务处理时,有几个关键词汇反复出现。下面是关于 事务处理需要知道的几个术语:

  • 事务(transaction)指一组SQL语句;
  • 回退(rollback)指撤销指定SQL语句的过程;
  • 提交(commit)指将未存储的SQL语句结果写入数据库表;
  • 保留点(savepoint)指事务处理中设置的临时占位符(place-holder),你可以对它发布回退(与回退整个事务处理不同)。

26.2 控制事务处理

STAR TRANSACTION来标记事务的开始

26.2.1 使用ROLLBACK

ROLLBACK来撤销INSERT,UPDATE,DELETE语句

SELECT * FROM orderitems;
START TRANSACTION;
DELETE FROM orderitems;
SELECT * FROM orderitems;

ROLLBACK;
SELECT * FROM orderitems;
26.2.2 使用COMMIT

COMMIT用来提交操作,只有在STARTCOMMIT之间的语句均不报错.这之间的语句才会提交.

START TRANSACTION;
DELETE FROM orderitems WHERE order_num = 20010;
DELETE FROM orders WHERE order_num = 20010;
COMMIT;
26.2.3 使用保留点
SAVEPOINT delete1;
ROLLBACK TO delete1;
26.2.4 更改默认的提交行为
SET autocommit = 0;

第28章 安全管理

pass

第29章 数据库维护

pass

第30章 改善性能

pass

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,236评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,867评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,715评论 0 340
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,899评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,895评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,733评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,085评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,722评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,025评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,696评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,816评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,447评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,057评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,254评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,204评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,561评论 2 343

推荐阅读更多精彩内容