文章目录

  • 一、表操作
  • 1、MySQL表数据类型
  • 1.1、MySQL数据类型
  • 1.2、MySQL数值数据类型
  • 1.3、MySQL布尔数据类型
  • 1.4、MySQL字符串数据类型
  • 1.5、MySQL日期和时间数据类型
  • 1.6、MySQL空间数据类型
  • 1.7、JSON数据类型
  • 2、用SQL语句创建表
  • 2.1、语句解释
  • 2.2、设定列类型 、大小、约束
  • 2.3、设定主键
  • 3、用SQL语句向表中添加数据
  • 3.1、语句解释
  • 3.2、多种添加方式(指定列名;不指定列名)
  • 4、用SQL语句删除表
  • 4.1、DELETE
  • 4.2、DROP
  • 4.3、TRUNCATE
  • 4.4、不同方式的区别
  • 5、用SQL语句修改表
  • 5.1、修改列名
  • 5.2、删除列
  • 5.3、新建列
  • 5.4、新建行
  • 5.5、删除行
  • 5.6、修改表中数据
  • 6、作业
  • 二、表联结
  • 1、MySQL别名
  • 2、INNER JOIN
  • 3、LEFT JOIN
  • 4、CROSS JOIN
  • 5、自连接
  • 6、UNION
  • 7、以上几种方式的区别和联系
  • 8、作业


一、表操作

1、MySQL表数据类型

1.1、MySQL数据类型

数据库表包含具有特定数据类型(如数字或字符串)的多个列。
 MySQL提供更多的数据类型,而不仅仅是数字或字符串。
 MySQL中数据类型都可以通过以下特征来确定:

	- 它用来表示数据值。
	- 占用的空间以及值是固定长度还是可变长度。
	- 数据类型的值可以被索引。
	- MySQL如何比较特定数据类型的值。

数据类型

指定值和范围

char

String(0~255)

varchar

String(0~255)

tinytext

String(0~255)

text

String(0~65536)

blob

String(0~65536)

mediumtext

String(0~16777215)

mediumblob

String(0~16777215)

longblob

String(0~4294967295)

longtext

String(0~4294967295)

tinyint

Integer(-128~127)

smallint

Integer(-32768~32767)

mediumint

Integer(-8388608~8388607)

int

Integer(-214847668~214847667)

bigint

Integer(-9223372036854775808~9223372036854775807)

float

decimal(精确到23位小数)

double

decimal(24~54位小数)

decimal

double转储为字符串形式

date

YYYY-MM-DD

datetime

YYYY-MM-DD HH:MM:SS

timestamp

YYYYMMDDHHMMSS

time

HH:MM:SS

enum

选项值之一

set

选项值子集

boolean

tinyint(1)

1.2、MySQL数值数据类型

数字类型

描述

TINYINT

一个很小的整数

SMALLINT

一个小的整数

MEDIUMINT

一个中等大小的整数

INT

一个标准整数

BIGINT

一个大整数

DECIMAL

定点数

FLOAT

单精度浮点数

DOUBLE

双精度浮点数

BIT

一个字节字段

1.3、MySQL布尔数据类型

MySQL没有内置的`BOOLEAN`或`BOOL`整数,所以要表示布尔值,MySQL使用最小的整数类型。也就是`TINYINT(1)`。
换句话说,`BOOLEN`和`BOOL`是`TINYINT(1)`的同义词。

1.4、MySQL字符串数据类型

在MySQL中,字符串可以容纳从纯文本到二进制数据(如图像或文件)的任何内容。
可以通过使用`LIKE`运算符,正则表达式和全文搜索,根据模式来比较和搜索字符串。

字符串类型

描述

char

固定长度的非二进制(字符)字符串

varchar

可变长度的非二进制字符串

BINARY

一个固定长度的二进制字符串

VARBINARY

一个可变长度的二进制字符串

TINYBLOB

一个非常小的BLOB(二进制大对象)

BLOB

一个小的BLOB(二进制大对象)

MEDIUMBLOB

一个中等大小的BLOB(二进制大对象)

LONGBLOB

一个大的BLOB(二进制大对象)

TINYTEXT

一个非常小的非二进制字符串

TEXT

一个小的非二进制字符串

MEDIUMTEXT

一个中等大小的非二进制字符串

LONGTEXT

一个很大的非二进制字符串

ENUM

枚举; 每个列值可以被分配一个枚举成员

SET

集合; 每个列值可以分配零个或多个SET成员

1.5、MySQL日期和时间数据类型

MySQL提供日期和时间的类型以及日期和时间的组合。
此外,MySQL还支持时间戳数据类型,用于跟踪表的一行中的更改。
如果只想存储没有日期和月份的年份数据,则可以使用`YEAR`数据类型。

字符串类型

描述

DATE

YYYY-MM-DD格式的日期值

TIME

hh:mm:ss格式的时间值

DATETIME

YYYY-MM-DD hh:mm:ss格式的日期和时间值

TIMESTAMP

YYYY-MM-DD hh:mm:ss格式的时间戳记值

YEAR

YYYYYY格式的年值

1.6、MySQL空间数据类型

字符串类型

描述

GEOMETRY

任何类型的空间值

POINT

一个点(一对X-Y坐标)

LINESTRING

曲线(一个或多个POINT值)

POLYGON

多边形

GEOMETRYCOLLECTION

GEOMETRY值的集合

MULTILINESTRING

LINESTRING值的集合

MULTIPOINT

POINT值的集合

MULTIPOLYGON

POLYGON值的集合

1.7、JSON数据类型

2、用SQL语句创建表

2.1、语句解释

创建新表:CERATE TABLE语句
简单的形式说明语法:

CERATE TABLE [IF NOT EXISTS] table_name(
     	column_list
     )engine=table_type;
  • 首先,指定CERATE TABLE子句之后创建的表名称。表名在数据库中必须是唯一的。IF NOT EXISTS是语句的可选部分,允许检查正在创建的表是否存在于数据库中。如果存在,MySQL会忽略整个语句,不会创建任何新的表。建议使用。
  • 其次,在column_list部分指定表的列表。字段的列用逗号(,)分隔。
  • 需要为 engine子句中的表指定存储引擎。可以使用任何引擎,默认使用InnoDB。

2.2、设定列类型 、大小、约束

column_name_data_type[size] [NOT NULL|NULL] [DEFAULT value]
     [AUTO_INCREMENT]
  • column_name指定列的名称。每列具有特定数据类型和大小,例如:VARCHAR(255)
  • NOT NULL或者NULL表示该列是否接受NULL值。
  • DEFAULT值用于指定列的默认值。
  • AUTO_INCREMENT指示每当将新行插入到表中时,列的值会自动增加。每个表都有一个且只有一个AUTO_INCREMENT列。

2.3、设定主键

使用以下语法:

PRIMARY KEY (col1,col2,col3,……)

数据库创建示例

mysql数据操作 mysql数据操作笔记_数据类型

3、用SQL语句向表中添加数据

3.1、语句解释

使用INSERT关键字。
INSERT语句的语法:

INSERT INTO table(column1,column2,……)
     VALUES(value1,value2,……);
  • INSERT INTO子句之后,在括号内指定表名和逗号分隔列的列表。
  • 将括号内的相应列的逗号分隔值放在VALUES关键字之后。

3.2、多种添加方式(指定列名;不指定列名)

指定列名

INSERT INTO tasks(SUBJECT,start_date,end_date,description)
  VALUES('Learn MySQL INSERT','2017-07-21','2017-07-22','Start learning..');

  SELECT * FROM tasks;

查询结果

mysql数据操作 mysql数据操作笔记_mysql数据操作_02


不指定列名

为表中所有列指定相应列的值,可以不指定列名添加。

INSERT INTO tasks
  VALUES('Learn MySQL INSERT','2017-07-21','2017-07-22','Start learning..');

  SELECT * FROM tasks;

与上方效果相同。

4、用SQL语句删除表

4.1、DELETE

语法

DELETE FROM table_name
WHERE condition;
  • 指定删除数据的表(table_name
  • 使用条件来指定要在WHERE子句中删除的行记录。如果行匹配条件,这些行记录将被删除。省略WHERE子句,DELETE语句将删除表中的所有行。

除了删除数据外,DELETE语句返回删除的行数。

限制删除的行数

DELETE FROM table
LIMIT row_count;

请注意,表中的行顺序未指定,因此,当使用LIMIT子句时,应始终使用ORDER BY子句,不然删除的记录可能不是预期的那样。

4.2、DROP

删除数据库DROP DATABASE

DROP DATABASE [IF EXISTS] database_name;

删除数据库意味着数据库中的所有数据和关联对象将被永久删除,并且无法撤销。
IF EXISTS是该语句的可选部分,以防止您删除数据库服务器中不存在的数据库。

4.3、TRUNCATE

TRUNCATE table_name;

清除表内内容,保留表结构。

4.4、不同方式的区别

  • 需要永久删除,使用DROP
  • 只需要删除表内内容,保留表结构,使用TRUNCATE
  • 删除部分记录,使用DELETE

5、用SQL语句修改表

使用ALTER TABLE更改现有表的结构。

ALTER TABLE table_name action1[,action2,…]
  • ALTER TABLE子句之后指定要更改的表名称。
  • 列出一组要应用于该表的操作。操作可以是添加新列,添加主键,重命名表等任何操作。ALTER TABLE语句允许在单个ALTER TABLE语句中应用多个操作,每个操作由逗号(,)分隔。

5.1、修改列名

ALTER TABLE table_name 
CHANGE 原列名 新列名 数据类型 约束;

慎重使用,注意数据类型不能省略。

5.2、删除列

ALTER TABLE table_name 
DROP COLUMN 列名;

5.3、新建列

ALTER TABLE table_name 
ADD COLUMN 列名 数据类型;

可以使用FIRSTALTER 列名指定新建列的位置。

5.4、新建行

使用INSERT INTO语句。

5.5、删除行

使用DELETE WHERE语句。

5.6、修改表中数据

UPDATE table_name 
SET 列1=值1,列2=值2 
WHERE 条件;

6、作业

//创建course表,有student学生和class班级字段
CREATE TABLE course(
	student VARCHAR(10),
	class VARCHAR(10)
);

//插入数据
INSERT INTO course 
VALUES
	('A','Math'),
	('B','English'),
	('C','Math'),
	('D','Biology'),
	('E','Math'),
	('F','Computer'),
	('G','Math'),
	('H','Math'),
	('I','Math'),
	('A','Math');

//查询结果
SELECT * FROM course;
+---------+----------+
| student | class    |
+---------+----------+
| A       | Math     |
| B       | English  |
| C       | Math     |
| D       | Biology  |
| E       | Math     |
| F       | Computer |
| G       | Math     |
| H       | Math     |
| I       | Math     |
| A       | Math     |
+---------+----------+

//查询所有超过或等于5名学生的课程(学生在每个课中不应被重复计算)
SELECT class FROM course GROUP BY class
HAVING COUNT(DISTINCT student) >= 5;
+-------+
| class |
+-------+
| Math  |
+-------+
//创建一个salary表,有m=男性和f=女性的值。
CREATE TABLE salary(
	id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
	NAME VARCHAR(10) NOT NULL,
	sex CHAR(2)  NOT NULL,
	salary VARCHAR(10) NOT NULL 
);
INSERT INTO salary
VALUES
	(1,'A','m',2500),
	(2,'B','f',1500),
	(3,'C','m',5500),
	(4,'D','f',500);
	
SELECT * FROM salary;
+----+------+-----+--------+
| id | name | sex | salary |
+----+------+-----+--------+
|  1 | A    | m   | 2500   |
|  2 | B    | f   | 1500   |
|  3 | C    | m   | 5500   |
|  4 | D    | f   | 500    |
+----+------+-----+--------+

//交换所有的f值和m值
//第一种方法
UPDATE salary SET sex = (
	CASE sex
	WHEN 'f'
	THEN 'm'
	WHEN 'm'
	THEN 'f'
	END
);
SELECT * FROM salary;
+----+------+-----+--------+
| id | name | sex | salary |
+----+------+-----+--------+
|  1 | A    | f   | 2500   |
|  2 | B    | m   | 1500   |
|  3 | C    | f   | 5500   |
|  4 | D    | m   | 500    |
+----+------+-----+--------+
//第二种方法
UPDATE salary SET sex = IF(
	sex = 'm','f','m'
);
SELECT * FROM salary; //与上面的结果比较
+----+------+-----+--------+
| id | name | sex | salary |
+----+------+-----+--------+
|  1 | A    | m   | 2500   |
|  2 | B    | f   | 1500   |
|  3 | C    | m   | 5500   |
|  4 | D    | f   | 500    |
+----+------+-----+--------+

二、表联结

1、MySQL别名

通过使用SQL语言,可以为表名称或列名称指定别名。使用AS关键字。
创建别名是为了让列名称的可读性更强。

//列的SQL别名语法:
SELECT column_name AS alias_name//提示:如果列名称包含空格,要求使用双引号或方括号
FROM table_name;

//表的 SQL 别名语法:
SELECT column_name(s)
FROM table_name AS alias_name;
//列的别名示例1:指定了两个别名,一个是 name 列的别名,一个是 country 列的别名。
SELECT name AS n, country AS c
FROM Websites;

//列的别名示例2:把三个列(url、alexa 和 country)结合在一起,并创建一个名为 "site_info" 的别名。
SELECT name, CONCAT(url, ', ', alexa, ', ', country) AS site_info
FROM Websites;
//表的别名实例:使用 "Websites" 和 "access_log" 表,并分别为它们指定表别名 "w" 和 "a"(通过使用别名让 SQL 更简短):
SELECT w.name, w.url, a.count, a.date 
FROM Websites AS w, access_log AS a 
WHERE a.site_id=w.id and w.name="教程";

//如果不使用别名:(与上面SQL语句效果相同)
SELECT Websites.name, Websites.url, access_log.count, access_log.date 
FROM Websites, access_log 
WHERE Websites.id=access_log.site_id and Websites.name="教程";

在以下情况中应使用别名

  • 在查询中涉及超过一个表
  • 在查询中使用了函数
  • 列名称很长或者可读性差
  • 需要把两个列或者多个列结合在一起

2、INNER JOIN

内连接或等值连接,获取两个表中字段匹配关系的记录。

mysql数据操作 mysql数据操作笔记_字符串_03

//在RUNOOB数据库中存在这样两张表:
mysql> use RUNOOB;
Database changed
mysql> show tables;
+------------------+
| Tables_in_runoob |
+------------------+
| runoob_tbl       |
| tcount_tbl       |
+------------------+
2 rows in set (0.01 sec)

mysql> select * from tcount_tbl;
+---------------+--------------+
| runoob_author | runoob_count |
+---------------+--------------+
| 菜鸟教程      |           10 |
| RUNOOB.COM    |           20 |
| Google        |           22 |
+---------------+--------------+
3 rows in set (0.00 sec)

mysql> select * from runoob_tbl;
+-----------+---------------+---------------+-----------------+
| runoob_id | runoob_title  | runoob_author | submission_date |
+-----------+---------------+---------------+-----------------+
|         1 | 学习 PHP      | 菜鸟教程      | 2017-04-12      |
|         2 | 学习 MySQL    | 菜鸟教程      | 2017-04-12      |
|         3 | 学习 Java     | RUNOOB.COM    | 2015-05-01      |
|         4 | 学习 Python   | RUNOOB.COM    | 2016-03-06      |
|         5 | 学习 C        | FK            | 2017-04-05      |
+-----------+---------------+---------------+-----------------+
5 rows in set (0.00 sec)

//使用MySQL的INNER JOIN(也可以省略 INNER 使用 JOIN,效果一样)来连接以上两张表来读取runoob_tbl表中所有runoob_author字段在tcount_tbl表对应的runoob_count字段值:
mysql> select a.runoob_id,a.runoob_author,b.runoob_count
    -> from runoob_tbl a
    -> inner join tcount_tbl b
    -> on a.runoob_author = b.runoob_author;
+-----------+---------------+--------------+
| runoob_id | runoob_author | runoob_count |
+-----------+---------------+--------------+
|         1 | 菜鸟教程      |           10 |
|         2 | 菜鸟教程      |           10 |
|         3 | RUNOOB.COM    |           20 |
|         4 | RUNOOB.COM    |           20 |
+-----------+---------------+--------------+
4 rows in set (0.01 sec)

3、LEFT JOIN

左连接,获取左表中所有记录,即使右表没有对应匹配的记录。

mysql数据操作 mysql数据操作笔记_数据类型_04

//以 runoob_tbl 为左表,tcount_tbl 为右表
mysql> select a.runoob_id,a.runoob_author,b.runoob_count
    -> from runoob_tbl a
    -> left join tcount_tbl b
    -> on a.runoob_author = b.runoob_author;
+-----------+---------------+--------------+
| runoob_id | runoob_author | runoob_count |
+-----------+---------------+--------------+
|         1 | 菜鸟教程      |           10 |
|         2 | 菜鸟教程      |           10 |
|         3 | RUNOOB.COM    |           20 |
|         4 | RUNOOB.COM    |           20 |
|         5 | FK            |         NULL |
+-----------+---------------+--------------+
5 rows in set (0.00 sec)

4、CROSS JOIN

CROSS JOIN将返回第一个表中的每一行与第二个表中的每一行组合在一起的所有记录。这也意味着CROSS JOIN返回连接表中行集的笛卡尔积。
CROSS JOIN使用:可以以两种方式来指定JOIN或语法通过列出在表FROM由逗号分隔的条款,而无需使用WHERE子句供给联接标准。
SQL CROSS JOIN语法:

SELECT * FROM [表1] CROSS JOIN [表2]

SELECT * FROM [表1],[表2]

mysql> select * from runoob_tbl cross join tcount_tbl;
+-----------+---------------+---------------+-----------------+---------------+--------------+
| runoob_id | runoob_title  | runoob_author | submission_date | runoob_author | runoob_count |
+-----------+---------------+---------------+-----------------+---------------+--------------+
|         1 | 学习 PHP      | 菜鸟教程      | 2017-04-12      | 菜鸟教程      |           10 |
|         1 | 学习 PHP      | 菜鸟教程      | 2017-04-12      | RUNOOB.COM    |           20 |
|         1 | 学习 PHP      | 菜鸟教程      | 2017-04-12      | Google        |           22 |
|         2 | 学习 MySQL    | 菜鸟教程      | 2017-04-12      | 菜鸟教程      |           10 |
|         2 | 学习 MySQL    | 菜鸟教程      | 2017-04-12      | RUNOOB.COM    |           20 |
|         2 | 学习 MySQL    | 菜鸟教程      | 2017-04-12      | Google        |           22 |
|         3 | 学习 Java     | RUNOOB.COM    | 2015-05-01      | 菜鸟教程      |           10 |
|         3 | 学习 Java     | RUNOOB.COM    | 2015-05-01      | RUNOOB.COM    |           20 |
|         3 | 学习 Java     | RUNOOB.COM    | 2015-05-01      | Google        |           22 |
|         4 | 学习 Python   | RUNOOB.COM    | 2016-03-06      | 菜鸟教程      |           10 |
|         4 | 学习 Python   | RUNOOB.COM    | 2016-03-06      | RUNOOB.COM    |           20 |
|         4 | 学习 Python   | RUNOOB.COM    | 2016-03-06      | Google        |           22 |
|         5 | 学习 C        | FK            | 2017-04-05      | 菜鸟教程      |           10 |
|         5 | 学习 C        | FK            | 2017-04-05      | RUNOOB.COM    |           20 |
|         5 | 学习 C        | FK            | 2017-04-05      | Google        |           22 |
+-----------+---------------+---------------+-----------------+---------------+--------------+
15 rows in set (0.00 sec)

5、自连接

自连接就是同一张表的不同列连接在一起,也就是自我连接。

mysql> select a.runoob_id,a.runoob_author,b.runoob_count
    -> from runoob_tbl a,tcount_tbl b
    -> where a.runoob_author = b.runoob_author;
+-----------+---------------+--------------+
| runoob_id | runoob_author | runoob_count |
+-----------+---------------+--------------+
|         1 | 菜鸟教程      |           10 |
|         2 | 菜鸟教程      |           10 |
|         3 | RUNOOB.COM    |           20 |
|         4 | RUNOOB.COM    |           20 |
+-----------+---------------+--------------+
4 rows in set (0.00 sec)

6、UNION

MySQL UNION 操作符用于连接两个以上的 SELECT 语句的结果组合到一个结果集合中。多个 SELECT 语句会删除重复的数据。

//MySQL UNION 操作符语法格式:
SELECT expression1, expression2, ... expression_n
FROM tables
[WHERE conditions]
UNION [ALL | DISTINCT]
SELECT expression1, expression2, ... expression_n
FROM tables
[WHERE conditions];

参数:

  • expression1, expression2, … expression_n: 要检索的列。
  • tables: 要检索的数据表。
  • WHERE conditions: 可选, 检索条件。
  • DISTINCT: 可选,删除结果集中重复的数据。默认情况下 UNION 操作符已经删除了重复数据,所以 DISTINCT 修饰符对结果没啥影响。
  • ALL: 可选,返回所有结果集,包含重复数据。
//从"runoob_tbl"表和"tcount_tbl"表中选取所有不同的runoob_author(只有不同的值):
mysql> select runoob_author from runoob_tbl
    -> union
    -> select runoob_author from tcount_tbl
    -> order by runoob_author;
+---------------+
| runoob_author |
+---------------+
| FK            |
| Google        |
| RUNOOB.COM    |
| 菜鸟教程      |
+---------------+
4 rows in set (0.01 sec)

//使用union all从"runoob_tbl"表和"tcount_tbl"表中选取所有的runoob_author(也有重复的值):
mysql> select runoob_author from runoob_tbl
    -> union all
    -> select runoob_author from tcount_tbl
    -> order by runoob_author;
+---------------+
| runoob_author |
+---------------+
| FK            |
| Google        |
| RUNOOB.COM    |
| RUNOOB.COM    |
| RUNOOB.COM    |
| 菜鸟教程      |
| 菜鸟教程      |
| 菜鸟教程      |
+---------------+
8 rows in set (0.00 sec)

7、以上几种方式的区别和联系

  • INNER JOIN:内连接或等值连接,获取两个表中字段匹配关系的记录。
  • LEFT JOIN:左连接,获取左表中所有记录,即使右表没有对应匹配的记录。
  • CROSS JOIN:将返回第一个表中的每一行与第二个表中的每一行组合在一起的所有记录。笛卡尔积
  • 自连接:同一张表的不同列连接在一起,也就是自我连接。
  • UNION :用于连接两个以上的 SELECT 语句的结果组合到一个结果集合中。多个 SELECT 语句会删除重复的数据。

8、作业

mysql> use program;
Database changed
mysql> create table Person(
    -> PersonId int(11) primary key,
    -> FirstName varchar(10),
    -> LastName varchar(10)
    -> );
Query OK, 0 rows affected (0.82 sec)

mysql> desc Person;
+-----------+-------------+------+-----+---------+-------+
| Field     | Type        | Null | Key | Default | Extra |
+-----------+-------------+------+-----+---------+-------+
| PersonId  | int(11)     | NO   | PRI | NULL    |       |
| FirstName | varchar(10) | YES  |     | NULL    |       |
| LastName  | varchar(10) | YES  |     | NULL    |       |
+-----------+-------------+------+-----+---------+-------+
3 rows in set (0.01 sec)

mysql> create table Address(
    -> AddressId int(11) primary key,
    -> PersonId int(11),
    -> City varchar(10),
    -> State varchar(10)
    -> );
Query OK, 0 rows affected (0.97 sec)

mysql> desc Address;
+-----------+-------------+------+-----+---------+-------+
| Field     | Type        | Null | Key | Default | Extra |
+-----------+-------------+------+-----+---------+-------+
| AddressId | int(11)     | NO   | PRI | NULL    |       |
| PersonId  | int(11)     | YES  |     | NULL    |       |
| City      | varchar(10) | YES  |     | NULL    |       |
| State     | varchar(10) | YES  |     | NULL    |       |
+-----------+-------------+------+-----+---------+-------+
4 rows in set (0.01 sec)

mysql> insert into Person
    -> values(1,'A1','B1'),(2,'A2','B2'),(3,'A3','B3');
Query OK, 3 rows affected (0.15 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> select * from Person;
+----------+-----------+----------+
| PersonId | FirstName | LastName |
+----------+-----------+----------+
|        1 | A1        | B1       |
|        2 | A2        | B2       |
|        3 | A3        | B3       |
+----------+-----------+----------+
3 rows in set (0.00 sec)

mysql> insert into Address
    -> values(1,2,'a1','b1'),(2,3,'a2','b2'),(3,1,'a3','b3');
Query OK, 3 rows affected (0.22 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> select * from Address;
+-----------+----------+------+-------+
| AddressId | PersonId | City | State |
+-----------+----------+------+-------+
|         1 |        2 | a1   | b1    |
|         2 |        3 | a2   | b2    |
|         3 |        1 | a3   | b3    |
+-----------+----------+------+-------+
3 rows in set (0.00 sec)

//SQL查询,无论 person 是否有地址信息,都需要基于上述两表提供 person 的以下信息:FirstName, LastName, City, State
mysql> select p.FirstName,p.LastName,a.City,a.State
    -> from Person p
    -> left join Address a
    -> on p.PersonId = a.PersonId;
+-----------+----------+------+-------+
| FirstName | LastName | City | State |
+-----------+----------+------+-------+
| A2        | B2       | a1   | b1    |
| A3        | B3       | a2   | b2    |
| A1        | B1       | a3   | b3    |
+-----------+----------+------+-------+
3 rows in set (0.00 sec)
//编写一个 SQL 查询,来删除 email 表中所有重复的电子邮箱,重复的邮箱里只保留 ID 最小 的那个。
mysql> select * from email;
+----+---------+
| ID | Email   |
+----+---------+
|  1 | a@b.com |
|  2 | c@d.com |
|  3 | a@b.com |
+----+---------+
3 rows in set (0.30 sec)

mysql> delete e1 from email e1
    -> left join email e2
    -> on e1.Email = e2.Email
    -> where e1.ID>e2.ID;
Query OK, 1 row affected (0.26 sec)

mysql> select * from email;
+----+---------+
| ID | Email   |
+----+---------+
|  1 | a@b.com |
|  2 | c@d.com |
+----+---------+
2 rows in set (0.00 sec)