文章目录
学习目标:
- 对表数据的增删改查
- 学习并熟练使用约束
- 简单查询
- 单表查询
- 多表查询
操作表数据
插入数据
插入所有字段
- 所有的字段名都写出来
INSERT INTO 表名 (字段名1, 字段名2, 字段名3…) VALUES (值1, 值2, 值3);
- 不写字段名
INSERT INTO 表名 VALUES (值1, 值2, 值3…);
插入部分字段
部分情况下有的字段默认是没有是数据的,比如备注,所以要用到插入部分字段
语法:
INSERT INTO 表名 (字段名1, 字段名2, ...) VALUES (值1, 值2, ...);
没有添加数据的字段会使用NULL
-
关键字说明
INSERT INTO 表名 – 表示往哪张表中添加数据 (字段名1, 字段名2, …) -- 要给哪些字段设置值 VALUES (值1, 值2, …); -- 设置具体的值
-
注意
- 值与字段必须对应,个数相同,类型相同
- 值的数据大小必须在字段的长度范围内
- 除了数值类型外,其它的字段类型的值必须使用引号引起。(建议单引号)
- 如果要插入空值,可以不写字段,或者插入null
更新数据
-
不带条件修改数据
UPDATE 表名 SET 字段名=值;
-
带条件修改数据
UPDATE 表名 SET 字段名=值 WHERE 字段名=值;
-
关键字说明
UPDATE: 修改数据 SET: 修改哪些字段 WHERE: 指定条件
-
具体操作:
-
不带条件修改数据,将所有的性别改成女
UPDATE student SET sex='女';
删除数据
-
不带条件删除数据
DELETE FROM 表名;
-
带条件删除数据
DELETE FROM 表名 WHERE 字段名=值;
-
truncate删除表记录
TRUNCATE TABLE 表名;
truncate和delete的区别:
- delete是将表中的数据一条一条删除
- truncate是将整个表摧毁,重新创建一个新的表,新的表结构和原来表结构一模一样
-
具体操作:
-
带条件删除数据,删除id为3的记录
DELETE FROM student WHERE id=3;
-
不带条件删除数据,删除表中的所有数据
DELETE FROM student;
约束
约束一般是在创建表时使用,用来控制表内数据,使其合理化
非空约束not null
该字段不能为null
唯一性约束unique
该字段不可重复,可以为null
主键约束primary key
非空+唯一+[自动增长]
唯一索引和主键的区别:
1、主键约束(primary key)
- 主键用于唯一地标识表中的每一条记录,可以定义一列或多列为主键。
- 是不可能(或很难)更新.
- 主键列上没有任何两行具有相同值(即重复值),不允许空(NULL).
- 主健可作外健,唯一索引不可;
2、唯一性约束(UNIQUE)
- 唯一性约束用来限制不受主键约束的列上的数据的唯一性,用于作为访问某行的可选手段,一个表上可以放置多个唯一性约束.
- 只要唯一就可以更新.
- 即表中任意两行在 指定列上都不允许有相同的值,允许空(NULL)
- 一个表上可以放置多个唯一性约束
默认值约束default
该字段有默认值,即不填写该字段时会自动填入默认值
检查约束check
检查是否符合条件
自动增长auto_increment
当前值=上一个值+1
外键约束foreign key
一般是另外一个有关联的主键
- 一对一关联:任意一方
- 一对多关联:外键放多的那边
- 多对多:用第三张表来存储两边的主键
具体案例:
CREATE TABLE IF NOT EXISTS t_user ( user_id INT comment 'id',
name VARCHAR(10) NOT NULL comment '姓名',-- 非空
sex VARCHAR(2) default '男' comment '性别',-- 默认
age INT(3) comment '年龄',
idcard VARCHAR(20) NOT NULL UNIQUE comment '身份证', -- UNIQUE唯一
primary key(user_id),-- 主键
CONSTRAINT 外键名 FOREIGN KEY(此表内的外键id) REFERENCES 连接的表名(id),
CHECK age>=0 );--检查
单表查询语句(Select)
查询不会对数据库中的数据进行修改.只是一种显示数据的方式
准备数据
CREATE TABLE student3 (
id int,
name varchar(20),
age int,
sex varchar(5),
address varchar(100),
math int,
english int
);
INSERT INTO student3(id,NAME,age,sex,address,math,english) VALUES (1,'马云',55,'男','杭州',66,78),(2,'马化腾',45,'女','深圳',98,87),(3,'马景涛',55,'男','香港',56,77),(4,'柳岩',20,'女','湖南',76,65),(5,'柳青',20,'男','湖南',86,NULL),(6,'刘德华',57,'男','香港',99,99),(7,'马德',22,'女','香港',99,99),(8,'德玛西亚',18,'男','南京',56,65);
简单查询
查询表所有数据
-
使用*表示所有列
SELECT * FROM 表名;
具体操作:SELECT * FROM student3;
-
写出查询每列的名称
SELECT 字段名1, 字段名2, 字段名3, ... FROM 表名;
具体操作:SELECT id, NAME ,age, sex, address, math, english FROM student3;
查询指定列
查询指定列的数据,多个列之间以逗号分隔
SELECT 字段名1, 字段名2... FROM 表名;
具体操作:
查询student3表中的id , name , age , sex , address 列
SELECT id, NAME ,age, sex, address FROM student3;
别名查询
1、“*”,表示按照create table的顺序排列的所有列。
2、表名.*,表示取回一个指定表中的所有列,适用于多表关联时,存在同名字段。列表中使用非限定列名,可能会产生解析错误。
2、按照用户所需顺序排列的列名的清单。
3、可以使用别名取代列名,形式如下:
column name as column_heading
mysql还支持不带as,直接空格跟别名的方式来指定别名。
4、表达式(列名、常量、函数,或以算术或逐位运算符连接的列名、常量和函数的任何组合)。
5、内部函数或集合函数。
6、上述各项的任何一种组合。
SQL的运算符
MySql中,数据库中的表结构确立后,表中的数据代表的意义就已经确定。而通过 MySQL 运算符进行运算,就可以获取到表结构以外的另一种数据。
例如,学生表中存在一个 birth 字段,这个字段表示学生的出生年份。而运用 MySQL 的算术运算符用当前的年份减学生出生的年份,那么得到的就是这个学生的实际年龄数据。
算术运算符
算术运算符是 SQL 中最基本的运算符,MySQL 中的算术运算符如下表所示。
算术运算符 | 说明 |
---|---|
+ | 加法运算 |
- | 减法运算 |
* | 乘法运算 |
/ | 除法运算,返回商 |
% | 求余运算,返回余数 |
注意:在除法运算和模运算中,如果除数为0,将是非法除法,返回结果为NULL。
加法减法没什么可以说的,我们先来说说乘法。
整数的乘法结果是整数。小数的乘法呢?
mysql> select 2*3 as t;
+---+
| t |
+---+
| 6 |
+---+
1 row in set (0.00 sec)
mysql> select 2.0*3.0 as t;
+------+
| t |
+------+
| 6.00 |
+------+
1 row in set (0.00 sec)
可以看到小数乘以小数,结果仍然是小数,我们需要关注精度,保留了乘数和被乘数的小数之和,系统并不会将小数点后的零自动去除。如果需要去除,则采用强制转换函数。
mysql> select 1.234 * 5.678 as t;
+----------+
| t |
+----------+
| 7.006652 |
+----------+
1 row in set (0.00 sec)
mysql> select convert(1.234 * 5.678, decimal(10,2)) as t;
+------+
| t |
+------+
| 7.01 |
+------+
1 row in set (0.00 sec)
MySQL 的CONVERT()函数可用来获取一个类型的值,并产生另一个类型的值。具体的语法如下:
CONVERT(value, type);
直接在sql中操作乘法的精度没问题,我们来看看字段操作怎么样。
create table ta (
aaa double,
bbb double,
ccc float,
ddd float,
eee decimal(10,2),
fff decimal(10,2)
);
insert into ta values (1.23, 2.34, 1.23, 2.34, 1.23, 2.34);
mysql> select aaa, bbb, aaa*bbb, ccc, ddd, ccc*ddd, eee, fff ,eee*fff from ta;
+------+------+--------------------+------+------+--------------------+------+------+---------+
| aaa | bbb | aaa*bbb | ccc | ddd | ccc*ddd | eee | fff | eee*fff |
+------+------+--------------------+------+------+--------------------+------+------+---------+
| 1.23 | 2.34 | 2.8781999999999996 | 1.23 | 2.34 | 2.8781999390602095 | 1.23 | 2.34 | 2.8782 |
+------+------+--------------------+------+------+--------------------+------+------+---------+
1 row in set (0.00 sec)
可以发现除了decimal,float和double的乘法操作都存在精度问题,需要强转。
可以发现:
sql里面直接数相乘,与字段中decimal相乘一致,结果小数位数保留被乘数乘数之和。
double类型数相乘,结果的精度高于float数相乘。
提示:能用decimal,就不要用float和double。
除法操作,我们也来看看精度问题。跟乘法类似,
进一步尝试
select 1.22345 / 2.3456;
insert into ta values (1.2345, 2.3456, 1.2345, 2.3456, 1.2345, 2.3456);
select aaa, bbb, aaa/bbb, ccc, ddd, ccc/ddd, eee, fff ,eee/fff from ta where aaa=1.2345;
可以发现:
sql里面直接数相除,与字段中decimal相除一致,结果小数位数保留被除数除数之和。
double类型数相除,结果的精度高于float数相除。
比较运算符
select语句中的条件语句经常要使用比较运算符。通过这些比较运算符,可以判断表中的哪些记录时符合条件的,比较结果为真,则返回1,为假则返回0,比较结果不确定则返回NULL。
select 1<2;
符号 | 描述 | 备注 |
---|---|---|
= | 等于 | |
<>,!= | 不等于 | |
> | 大于 | |
< | 小于 | |
>= | 大于等于 | |
<= | 小于等于 | |
BETWEEN | 在两值之间 | >=max&&<=min |
NOT BETWEEN | 不在两值之间 | |
IN | 在集合中 | |
NOT IN | 不在集合中 | |
<=> | 严格比较两个NULL值是否相等 | 两个操作码均为NULL时,其所得值为1;而当一个操作码为NULL时,其所得值为0 |
LIKE | 模糊匹配 | |
EGEXP或RLIKE | 正则匹配 | |
IS NULL | 为空 | |
IS NOT NULL | 不为空 |
等于(==)与严格等于运算符(<=>)
严格等于和等于运算符(=)的作用一致,只不过多了一个功能,就是可以判断NULL值,如下:
select 1=0,'2'=2,(1+3)=(2+2),NULL=NULL;
select 1<=>0,'2'<=>2,(1+3)<=>(2+2),NULL<=>NULL;
不等于运算符(<>或!=)
不等于运算符用于判断数字、字符串、表达式是否不相等,如果不相等则返回 1,否则返回 0 ,但是不能判断 NULL 值。
IS NULL 、IS NOT NULL
- IS NULL是 检验一个值是否为 NULL ,如果为 NULL ,返回值为 1,否则返回值为 0;
- IS NOT NULL 检验一个值是否不为 NULL ,如果不为 NULL ,返回值为 1,否则返回值为 0。
BETWEEN AND
用于判断一个值是否落在两个值之间。
select 4 between 1 and 5,4 between 4 and 6,12 between 9 and 10;
between … and 操作符是包含两边端点的。
IN、NOT IN
- IN :判断一个值是否是 IN 列表中的任意一个值;
- NOT IN :判断一个值是否不是 IN 列表中的任意一个值。
select 2 in(3,5,8,2), 2 not in(1,3,5);
LIKE
- LIKE 运算符用来匹配字符串(正则表达式),如果匹配则返回 1,如果不匹配则返回 0;
- LIKE 使用两种通配符:‘%’ 用于匹配任何数目的字符,包括零字符 ; ‘_’ 只能匹配一个字符。
mysql> select 'stud' like 'stu_','stud' like 's___','stud' like '%d';
REGEXP
1)REGEXP运算符用来匹配字符串,如果匹配则返回1,如果不匹配则返回0;
2)REGEXP 使用以下几种通配符:
- ‘^’:用于匹配以什么开头的字符串;
- ‘$’:用以匹配以什么结尾的字符串;
- ‘.’:用于匹配任何一个单字符串;
- ‘[…]’:用于匹配在方括号内的任何字符;
- '*'用于匹配零个或多个在它前面的字符;
select 'ssky' regexp '^s', 'ssky' regexp 'y$', 'ssky' regexp '.sky', 'ssky' regexp '[ab]' ;
逻辑运算符
逻辑运算符用来判断表达式的真假。如果表达式是真,结果返回 1。如果表达式是假,结果返回 0。
运算符号 | 作用 |
---|---|
NOT或! | 逻辑非 |
AND | 逻辑与 |
OR | 逻辑或 |
XOR | 逻辑异或 |
逻辑非(NOT 或 !)
- 当操作数为 0 时,所得值为 1;
- 当操作数为非 0 时,所得值为 0;
- 当操作数为 NULL 时,所得值为 NULL。
mysql> select not 10,!10,not(1-1),!(1-1),not 1+1,not null;
逻辑与(AND或&&)
- 当所有操作数均为非零值、并且不为 NULL 时,所得值为 1;
- 当一个或多个操作数为 0 时,所得值为 0 ;
- 其余情况所得值为 NULL。
mysql> select 1 and -1,1 && 0,0 and null,1 && null;
逻辑或(OR 或 || )
- 当两个操作数均为非 NULL 值,且任意一个操作数为非零值时,结果为 1 ,否则为 0;
- 当有一个操作数为 NULL ,且另一个操作数为非零值时,则结果为 1 ,否则结果为 NULL;
- 当两个操作数均为 NULL 时,则所得结果为 NULL。
mysql> select 1 or -1 or 0,1 || 2,0 or null,null|| null;
逻辑异或(XOR)
- a XOR b 的计算等同于 ( a AND (NOT b) ) 或 ( (NOT a) AND b );
- 当任意一个操作数为 NULL 时,返回值为 NULL;
- 对于非 NULL 的操作数,如果两个操作数都是非 0 值或者都是 0 值,则返回结果为 0;
- 如果一个为 0 值,另一个为非 0 值,返回结果为 1。
mysql> select 1 xor 1,0 xor 0,1 xor 0,1 xor null,1 xor 1 xor 1;
运算符的优先级
最低优先级为: :=。
最高优先级为: !、BINARY、 COLLATE。
用(),千万记得用括号。
where子句
where子句设置了搜索条件。
它在insert,update,delete语句中的应用方法也与在select语句中的应用方法完全相同。搜索条件紧跟在关键词where的后面。如果用户要在语句中使用多个搜索条件,则可用and或or连接。
搜索条件的基本语法是
select * from test1 where aaa = '呵呵';
select* from test1 where not aaa = '呵呵';
select* from test1 where aaa != '呵呵';
distinct关键字的用法
在mysql中,distinct关键字的主要作用就是对数据库表中一个或者多个字段重复的数据进行过滤,只返回其中的一条数据给用户,distinct只可以在select中使用。
distinct的原理:
distinct进行去重的主要原理是通过先对要进行去重的数据进行分组操作,然后从分组后的每组数据中去一条返回给客户端,在这个分组的过程可能会出现两种不同的情况:
distinct 依赖的字段全部包含索引:
该情况mysql直接通过操作索引对满足条件的数据进行分组,然后从分组后的每组数据中去一条数据。
distinct 依赖的字段未全部包含索引:
该情况由于索引不能满足整个去重分组的过程,所以需要用到临时表,mysql首先需要将满足条件的数据放到临时表中,然后在临时表中对该部分数据进行分组,然后从临时表中每个分组的数据中去一条数据,在临时表中进行分组的过程中不会对数据进行排序。
GROUP BY 语句
GROUP BY 语句根据一个或多个列对结果集进行分组。
select bbb from test1 group by bbb;
--这其实跟distinct返回的结果一致
select distinct bbb from test1;
聚合函数
聚合函数aggregation function又称为组函数。 默认情况下 聚合函数会对当前所在表当做一个组进行统计,MySQL提供了许多聚合函数,包括AVG
,COUNT
,SUM
,MIN
,MAX
等。除COUNT
函数外,其它聚合函数在执行计算时会忽略NULL
值。
聚合函数的特点
1.每个组函数接收一个参数(字段名或者表达式),统计结果中默认忽略字段为NULL的记录
2.要想列值为NULL的行也参与组函数的计算,必须使用IFNULL函数对NULL值做转换。
3.不允许出现嵌套 比如sum(max(xx))
AVG函数
AVG()函数计算一组值的平均值。 它计算过程中是忽略NULL
值的。
select avg(bbb) from test1;
select aaa, avg(bbb) from test1 group by aaa;
如果select的字段列表除了聚合函数以外,没有其他字段,可以不用group by分组子句。否则必须搭配group by使用。
MAX()函数
MAX()函数返回一组值中的最大值,其语法如下所示 -
select aaa, max(bbb) from test1 group by aaa;
MIN()函数
MIN()函数返回一组值中的最小值,其语法如下所示 -
select aaa, min(bbb) from test1 group by aaa;
现在我们设想一个应用场景,计算公司部门的员工最高工资和最低工资,先创建表。
drop table emp;
create table emp(
emp_id int primary key auto_increment,
emp_name varchar(20) comment '员工姓名',
emp_dept varchar(20) comment '部门名称',
salary decimal(10, 2) comment '工资',
hiredate datetime comment '入职时间'
);
insert into emp(emp_name, emp_dept, salary, hiredate) values('赵大', '开发部', 4500, '2016-3-1');
insert into emp(emp_name, emp_dept, salary, hiredate) values('陈二', '开发部', 5000, '2015-5-6');
insert into emp(emp_name, emp_dept, salary, hiredate) values('张三', '开发部', 7000, '2012-7-4');
insert into emp(emp_name, emp_dept, salary, hiredate) values('李四', '测试部', 5500, '2015-3-5');
insert into emp(emp_name, emp_dept, salary, hiredate) values('王五', '测试部', 3500, '20180407');
insert into emp(emp_name, emp_dept, salary, hiredate) values('钱六', '销售部', 6000, '20170909');
insert into emp(emp_name, emp_dept, salary, hiredate) values('周七', '财务部', 5200, '20170709');
select * from emp;
我们要如何统计各个部门的最高工资和最低工资呢?
select emp_dept, max(salary) from emp group by emp_dept;
select emp_dept, min(salary) from emp group by emp_dept;
解释一下这个结果:
1、满足“SELECT子句中的列名必须为分组列或列函数”,因为SELECT有GROUP BY DEPT中包含的列DEPT。
2、“列函数对于GROUP BY子句定义的每个组各返回一个结果”,根据部门分组,对每个部门返回一个结果,就是每个部门的最高薪水。
3、分组查询可以在形成组和计算列函数之前具有消除非限定行的标准 WHERE 子句。必须在GROUP BY 子句之前指定 WHERE 子句。
select emp_dept, max(salary) from emp where hiredate between '20150101' and '2016-12-31' group by emp_dept;
COUNT()函数
COUNT()函数返回结果集中的行数。
select count(*) from emp;
select count(1) from emp;
select count(emp_id) from emp;
select emp_dept, count(emp_id) from emp group by emp_dept;
注意:count() 在统计时,会计入null值。
SUM()函数
SUM()函数返回一组值的总和,SUM()函数忽略NULL
值。如果找不到匹配行,则SUM()函数返回NULL
值。
select emp_dept, sum(salary) from emp group by emp_dept;
select emp_dept, sum(salary) from emp where emp_dept='aaa' group by emp_dept;
Order by 子句
如果我们需要对读取的数据进行排序,我们就可以使用 MySQL 的 ORDER BY 子句来设定你想按哪个字段哪种方式来进行排序,再返回搜索结果。
以下是 SQL SELECT 语句使用 ORDER BY 子句将查询数据排序后再返回数据:
SELECT field1, field2,...fieldN FROM table_name1, table_name2...
ORDER BY field1 [ASC [DESC][默认 ASC]], [field2...] [ASC [DESC][默认 ASC]]
- 你可以使用任何字段来作为排序的条件,从而返回排序后的查询结果。
- 你可以设定多个字段来排序。
- 你可以使用 ASC 或 DESC 关键字来设置查询结果是按升序或降序排列。 默认情况下,它是按升序排列。
我们来看几个例子
select * from emp order by salary;
--默认情况按升序排列
select * from emp order by salary desc;
--指定desc后按降序排列
select emp_dept, sum(salary) from emp group by emp_dept order by emp_dept;
--字符串也可以排序,排序依据为字符编码的二进制值
select emp_dept, sum(salary) from emp group by emp_dept order by emp_dept desc;
SELECT后被选择的列,可以在ORDER by和GROUP BY中,通过列名、列别名或者代表列位置的整数(从1开始)来引用。
select emp_dept, sum(salary) from emp group by emp_dept order by 1 desc;
用 union/union all来连接结果集
如果想选择其他几个表中的行或从一个单一的表作为一个单独的结果集行的几个集会,那么可以使用的UNION。
UNION 用于合并两个或多个 SELECT 语句的结果集,并消去表中任何重复行。如果允许重复的值,请使用 UNION ALL。我们来创建一个场景,学生表和教师表
create table teacher(
id int primary key auto_increment,
teacher_name varchar(20),
teacher_city varchar(20)
);
create table student(
id int primary key auto_increment,
student_name varchar(20),
student_city varchar(20)
);
insert into teacher(teacher_name, teacher_city) values('赵大', '武汉');
insert into teacher(teacher_name, teacher_city) values('陈二', '鄂州');
insert into teacher(teacher_name, teacher_city) values('张三', '襄阳');
insert into student(student_name, student_city) values('李四', '宜昌');
insert into student(student_name, student_city) values('王五', '恩施');
insert into student(student_name, student_city) values('钱六', '黄石');
insert into student(student_name, student_city) values('周七', '孝感');
我们用两个查询分别取得两个表的结果集,然后连接。
select * from teacher
union
select * from student;
如果要获取老师和学生来自哪些城市,则
select teacher_city from teacher
union
select student_city from student;
注意:
1、UNION 结果集中的列名总是等于第一个 SELECT 语句中的列名
2、UNION 内部的 SELECT 语句必须拥有相同数量的列。列也必须拥有相似的数据类型。同时,每条 SELECT 语句中的列的顺序必须相同。union只关注数据类型,数据业务含义是否相同不管。
我们再插入3条记录
insert into student(student_name, student_city) values('周七1', '武汉');
insert into student(student_name, student_city) values('周七2', '武汉');
insert into student(student_name, student_city) values('周七3', '武汉');
比较一下3句sql
select * from teacher
union
select * from student;
select teacher_city from teacher
union
select student_city from student;
select teacher_city from teacher
union all
select student_city from student;
union会将结果集去重,它比较结果集中的全部字段,所有字段都相同的将被去除。union all 不去重。
union的用法及注意事项
union:联合的意思,即把两次或多次查询结果合并起来。
要求:两次查询的列数必须一致
推荐:列的类型可以不一样,但推荐查询的每一列,想对应的类型以一样
可以来自多张表的数据:多次sql语句取出的列名可以不一致,此时以第一个sql语句的列名为准。
如果不同的语句中取出的行,有完全相同(这里表示的是每个列的值都相同),那么union会将相同的行合并, 最终只保留一行。也可以这样理解,union会去掉重复的行。
如果不想去掉重复的行,可以使用union all。
如果子句中有order by,limit,需用括号()包起来。推荐放到所有子句之后,即对最终合并的结果来排序或筛选。
select emp_dept, sum(salary) from emp group by emp_dept
union
select emp_dept, sum(salary) from emp group by emp_dept
order by emp_dept desc;
--或者这样
(select emp_dept, sum(salary) from emp group by emp_dept)
union all
(select emp_dept, sum(salary) from emp group by emp_dept)
order by emp_dept desc;
关联查询
左查询
以左表为主,左表记录一定全部查出来,右表只查符合记录的
语法:select ... from 表a left join 表b on 表a.字段名=表b.字段名;
即使左表所对应的为空也会查出来
右查询
以右表为主,右表记录一定全部查出来,左表只查符合记录的
语法:select ... from 表a right join 表b on 表a.字段名=表b.字段名;
即使右表所对应的为空也会查出来
内连接
只查左右两边符合记录的
语法:select ... from 表a inner join 表b on 表a.字段名=表b.字段名;
必须要两边都符合的
左外连接
以左表为主,如果匹配到就显示,匹配不到就显示为null
语法:select ... from 表a left join 表b on 表a.字段名=表b.字段名where 表b.key is null;
即使左表所对应的为空也会查出来
右外连接
以右表为主,如果匹配到就显示,匹配不到就显示为null
语法:select ... from 表a right join 表b on 表a.字段名=表b.字段名where 表a.key is null;
即使右表所对应的为空也会查出来
全外连接
把所有不关联的都显示出来
语法:
原本是full outer join,但MySQL并没有,所以只能用左连接+右外连接等
select ... from 表a right join 表b on 表a.字段名=表b.字段名where 表a.key is null;
union
select ... from 表a left join 表b on 表a.字段名=表b.字段名where 表b.key is null;
全连接
把所有关联和不关联的都显示出来
语法:
select ... from 表a right join 表b on 表a.字段名=表b.字段名;
union
select ... from 表a left join 表b on 表a.字段名=表b.字段名where 表b.key is null;
笛卡尔积
把所有的可能性都查出来,总数量为两边表行数的积
语法:select ... from 表a cross join 表b on 表a.字段名=表b.字段名;
冗余度高,能不用就别用