MySQL Notes 01

常用的数据库服务器:
商业:oracle、SQLserver、DB2
开源:MySQL、postgreSQL、SQLite
 
服务器 与 客户端 :
mysqld.exe ——MySQL服务器的进程。(始终运行)
mysql.exe ——MySQL客户端的进程。(官方自带的客户端)
 
(注意:能满足 MySQL 通讯规范的工具都可以做客户端。例如:navcat 、mysql_front 、phpMyAdmin(基于网页)。)
 
 
基础概念:
数据库服务器、数据库、表、字段(列)、记录(行)
 
什么是 结果集 ?
答:通过 select 语句 对 表 查询出来的结果 是放在内存中的缓存结果 即【结果集】。
 
什么是 表前缀 ?
答:表前缀用于表示该字段 属于哪张表。
格式:表名.字段名
例如:goods.cat_id
 
什么是 别名 ?
答:通过 as 对【表】或【结果集】中的字段(列)起的别名。可方便后续语句的调用。
 
 
连接 MySQL 数据库服务器:
命令:mysql -h 服务器:端口 -u用户名 -p密码
例如:mysql -h localhost:3306 -uadmin -p
 
注意:
① -p 之后可以直接输入密码,也可以‘回车’后再输入密码。前者密码是明文的(可见的),后者密码会用*代替。
 
② -h 之后的服务器可以用 IP 或 域名。且服务器默认为localhost。端口默认为3306。
 
 
★小技巧:
① 语句打错以后,可以用 \c 退出本句。
 
② 这个类似于sqlplus的spool功能,可以将命令行中的结果保存到外部文件中。如果指定已经存在的文件,则结果会附加到文件中。 
   例如:
tee D:\note_mysql.sql
或者 
\T D:\note_mysql.sql
 
 
 
一、MySQL入门语句:
 
显示所有的数据库:
show databases;
(注意:在所有的数据库中有3个数据库极其重要,其中保存有数据库服务器系统的相关信息,不可随意修改、删除。其分别为:information_schema 、mysql 、performance_schema。)
 
创建数据库:
create database 库名;
create database 库名 charset utf8; (加上字符集声明)
 
create database 库名 字符集声明,整理声明(即 排序规则);
 
删除数据库:
drop database 库名; (慎用!)
 
修改数据库:
一般极少会遇上要修改数据库的情况,就算改也只能改字符集和整理集。库名不能修改。
 
 
选择数据库:
use 库名;
 
显示当前数据库下所有的表:
show tables;
 
删除表:
drop table 表名;
 
修改表名:
rename table 旧的表名 to 新的表名; (慎用!)
 
查看表结构:
desc 表名;
 
创建表:
create table 表名(
字段名 数据类型,
字段名 数据类型
)
 
清空表:
truncate 表名;
 
查看创建表的语句:
show create table 表名;
 
 
 
 
二、列类型(字段的数据类型):
 
三大列类型:数值类型、字符串类型、日期时间类型。
 
 
数值类型,又分为 整数类型、小数类型:
 
整数类型:
tinyint 1字节(8位) 无符号:0~255 有符号:-128~127
smallint 2字节(16位) 无符号:0~65535 有符号:-32768~32767
mediumint 3字节(24位) 无符号:0~16777215 有符号:-8388608~8388607
int 4字节(32位) 无符号:0~4294967295 有符号:-2147483648~2147483647
bigint 8字节(64位) 无符号:0~18446744073709551615 有符号:-9223372036854775808~9223372036854775807
 
整型系统的可选参数:***int(M) unsigned zerofill
例如:age tinyint(4) unsigned; 或者 stunum smallint(6) zerofill;
 
unsigned 代表此列为无符号类型,会影响到列的存储范围(范围从0开始)。
 
★注意:如果不加 unsinged ,则默认是有符号类型,范围从负数开始。
 
zerofill 代表0填充,即:如果该数字不足参数 M 位,则自动在前面补0,补够 M 位。
 
★注意:
① 如果没有 zerofill 属性,只有参数 M ,则 参数 M 毫无意义。
 
② 如果设置某列为 zerofill ,则该列默认为无符号类型(unsigned)。
 
 
小数类型:
float(M,D) 浮点型,M 代表一共可以存储 M 位,D 代表小数点后可以有 D 位。
decimal(M,D) 定点型,M、D 意义同上。
 
★注意:
① 小数类型的 参数 M 与 整数类型的 参数 M 意义完全不同。
小数类型的 参数 M 是用来规定存储范围的。而 整数类型的 参数 M 不会影响存储范围,它只是规定0填充的宽度。
 
② 计算机保存的小数一般会有误差。关于十进制小数转二进制......
 
float 与 decimal 的区别:
① decimal 比 float 精度更高,适合存储货币等要求精确的数字。
 
② 所占空间的区别:
float(M,D) 如果 M<=23,则占4个字节(32位)。如果 24<=M<=53,则占8个字节(64位)。
decimal(M,D) 始终占8个字节(64位)。
 
 
字符串类型,分为 char 和 varchar :
 
char定长类型:
char(M),M代表宽度,0<=M<=255个字符 之间。
例:char(10),则能输入10个字符。
 
★注意:
① char(M)如何实现定长M个字符的宽度?
答:如果实际存储内容不足M个,则后面加空格补齐。取出来的时候,再把后面的空格去掉。
★正因如此,char定长类型 所保存的内容,若最后有空格,则会被清除。
 
② char 定长类型,查询速度快。因为每一行信息都定长为M个字符。
 
 
varchar变长类型:
varchar(M),M代表宽度,0<=M<=65535个字符(以ASCII字符集为例,如果是utf8 则22000个字符 左右)。
 
★注意:
① varchar 变长类型会在内容的前面加一个【长度信息说明】,用于实现变长。
 
② varchar 变长类型所占的空间 = 真实内容长度 + 长度信息说明(一般为1~2个字节)。
 
char 与 varchar 对比:
类型: 宽度: 可存字符: 实存字符(i<M): 实占空间: 利用率:
char   M   M i M i/M <= 100%
varchar  M M i i字符+1~2字节 i/(i+1~2字节) < 100%
 
char 与 varchar 的选择原则:
① 从 空间利用率 的角度:
例如: 四字成语表,就应该选择char(4)。
个人简介,微博 140字,就应该选择varchar(140)。
 
② 从 查询速度 的角度:
例如: 用户名,应该选择char
☆有某些大网站为了追求执行效率,会把常用varchar(变长)的地方都用char(定长),例如:用户名。
这是“用空间换时间”。毕竟现在硬盘越来越便宜。(2012年记录)
 
text文本类型:
text文本类型可以存放比较的的文本段,搜索速度稍慢。因此,如果不是特别大的内容,建议用 char 或 varchar 来代替。
 
★注意:text文本类型不用加默认值,加了也没用。
 
text文本类型最多可以存放两万多个字,适宜用来存放例如:新闻内容等长文本。
更大的字符串存储类型有:mediumtext、longtext 等,但这些都很少会用到。
 
 
日期/时间类型:
year   年 例如:95 或 1995 (支持范围:1901~2155,始终占1字节)
 
★注意:在 insert 时,可以简写年的后两位,但是不推荐。
因为当增加内容为 00~69 时,结果将会加2000,例如:增加内容为69 ,结果为 2069。
如果增加内容为 70~99 时,结果将会加1900,例如:增加内容为70 ,结果为 1970。
则,在增加内容时,简写年的后两位,不但容易出现,而且只能表示 1970~2069。
 
date   日期 例如:1998-07-31 (支持范围:1000-01-01 到 9999-12-31)
time    时间 例如:13:56:23 (支持范围:-838:59:59 到 838:59:59)
datetime  日期时间 例如:1998-07-31 13:56:23 (支持范围:1000-01-01 00:00:00 到 9999-12-31 23:59:59)
 
★注意:一般存储注册时间、商品发布时间等,并不用 datetime类型,而是用 int类型 存储时间戳。因为 datetime类型虽然直观,但不便于计算。
 
 
特殊的NULL类型:
NULL 不是假,也不是真,而是"空"。
任何运算符,判断符碰到NULL,都得NULL。
NULL的判断只能用 is null ,is not null 。
NULL 影响查询速度,一般避免使值为NULL。
因此:我们在创建表的时候,常常在声明字段时 加上 not null default 0
例如:
create table 表名(
字段名 数据类型 not null default 0,
字段名 数据类型 not null default 0
)
 
★ not null default 0 的意思是:该字段的值不允许为 NULL 且默认为0。
 
☆ 根据 MySQL 中 关系运算符 的运算结果是 0 或 1 ,以及 MySQL 中 逻辑运算符 的运算结果。本人认为:MySQL 中 0为假 非0为真。
 
 
 
三、增删改语法:
 
增:
insert into 表名 (列1,列2,......,列n) values(值1,值2,......,值n);
 
省略字段名(列名):
insert into 表名 values(值1,值2,......,值n);
 
★注意:如果省略字段名(列名)则对应的值必须与表中字段的个数和顺序一致。不能忽略 auto_increment 即 自增长 的字段。
 
改:
update 表名 set 列1=值1,列2=值2,......,列n=值n where 条件;
 
删:(删一行)
delete from 表名 where 条件;
 
 
 
 
四、查(select)及 5种子句:
 
查:
select 列1,列2,......,列n from 表名;
或,常用:
select * from 表名;
 
 
(1) where 子句:
作用:条件查询。(★从表中筛选。)
 
例如:
select * from 表名 where (列1 - 列2) > 200;
 
★注意:我们应该把‘列’当成‘变量’来看,即 列与列之间可以进行运算,例如:
select 列1,列2,列1 - 列2 from 表名 where (列1 - 列2) > 200;
 
 
  ★where常用运算符:
 
-----关系运算符-----
< 小于
<= 小于或等于
> 大于
>= 大于或等于
= 等于
!=或<> 不等于
in 在某集合内,例如:where 列1 in (2,5,8); #意思是取出 列1 等于 2 或 5 或 8 的记录。
between 在某范围内,例如:where 列1 between 2 and 8; #意思是取出 列1 等于 2 至 8 的记录。
 
☆ 在 MySQL 中 关系运算符 的运算结果是 0 或 1 。
 
-----逻辑运算符-----
NOT 或 ! 逻辑非,例如:where not 列1 between 2 and 8; #意思是取出 列1 不等于 2 至 8 的记录(即 列1小于2 或 列1大于8 的记录)。
OR 或 || 逻辑或,例如:where 列1 < 2 or 列1 > 8; #意思是取出 列1小于2 或 列1大于8 的记录。
AND 或 && 逻辑与,例如:where 列1 > 2 and 列1 < 8; #意思是取出 列1大于2 且 列1小于8 的记录(即 2 至 8 的记录)。
 
★注意:AND 比 OR 的优先级更高。
 
☆ 根据测试,本人认为 MySQL 中的 逻辑运算符 也具有 短路特性 。
 
☆ 根据 MySQL 中 关系运算符 的运算结果是 0 或 1 ,以及 MySQL 中 逻辑运算符 的运算结果。本人认为:MySQL 中 0为假 非0为真。
 
 
  ★模糊匹配:like
例如:where 列1 like '苹果%';
 
通配符:
% 表示 通配任意字符。例如:where 列1 like '苹果%';
_ 表示 通配单一字符。例如:where 列1 like '苹果iphone__s';
 
 
 
(2) group by 子句:
作用:分组。
 
  ★聚合函数:
avg() 求平均值,例如:select avg(列1) from 表名;
sum() 求和
max() 求最大值
min() 求最小值
count() 求总行数(沿着每一行,数一遍),例如:select count(*) from 表名;
 
☆ count() 详解:
 
根据 MySQL 官方文档 可知,其实 count 函数 的作用是:
 
    count(表达式)
    返回 该表达式 结果非NULL 的行数。
 
事实上,当 count 函数 的参数为 NULL 时不会进行计算,当参数 非NULL 时都会进行计算(当参数为 0 时也会进行计算)。
 
    例如,假设有某表 tb :
 
    select count(null) from tb;    #不会把任何一行计算在内。
    select count(*) from tb;    #把每一行都计算在内。
    select count(0) from tb;    #把每一行都计算在内。
    select count(1) from tb;    #把每一行都计算在内。
    select count(2) from tb;    #把每一行都计算在内。
 
    假设 n 是 tb 表 中的一个字段。在某行记录中 n 字段的值为 100 :
 
    select count(n < 50) from tb;
    #不会跳过该行(把该行计算在内)。因为在该行中 n 的值为 100, n < 50 的运算结果为 0 。
   
    select count(n < 50 or null) from tb;
    #跳过该行(不会进行计算)。n < 50 的运算结果为 0 ,但因为 or 的 短路特性 所以表达式的结果为 NULL 。
 
 
☆ “字段” 即 “变量” :
 
在 MySQL 中,如果函数被调用时,其参数中出现了某个字段名(列名),那么函数就会取每一行记录中对应字段(列)的值 代入参数中进行处理。
 
这里 字段名(列名)就像是 变量名 ,每行记录中 该字段(列)的值 就像是 变量的值 。
 
where、having子句 及 select 等语句也同上。例如:
 
select 列1,列2,列1 - 列2 from 表名 where (列1 - 列2) > 200;
 
所以我们应该把 字段名 视为 变量名,字段 视为 变量。
 
 
  ★注意:若在查询语句中使用 聚合函数 则其只会返回单个值(仅返回一行,并且 返回值 与该行中的其他字段无直接关系!)。
因此 无法通过 max()、min() 直接完成 “查询商品表中最贵、最便的商品” 之类的要求。
 
  ★按 SQL 标准,若在查询时使用 group by 子句,则其查询的字段(非聚合函数作用的字段)只能是跟在 "group by" 后面的字段(字段名)。
但 MySQL 允许查询不属于 group by 中的字段,而且取第一次出现的行。勿用这种方法,否则当代码移植到其他数据库(例如:Oracle)时将出现大问题。
 
 
结合 聚合函数 进行分组处理,例如:
 
  1.查询 每个栏目下的 商品价格的 平均值:(★系统会先根据 cat_id 字段进行分组,再分别求出每组中 shop_price 字段的平均值。)
select cat_id,avg(shop_price) from 商品表 group by cat_id;
 
  2.查询 每个栏目下有多少种商品:
select cat_id,count(*) from 商品表 group by cat_id;
 
  3.查询 每个栏目下最贵的商品价格:
select cat_id,max(shop_price) from 商品表 group by cat_id;
 
  4.查询 本网站,积压的货款总量:(提示:货款总量 = 商品库存 * 商品价格)
select cat_id,sum(goods_number * shop_price) from 商品表;
 
  5.查询 每个栏目下积压的货款总量:
select cat_id,sum(goods_number * shop_price) from 商品表 group by cat_id;
 
  6.查询 积压货款总量 > 20000 的栏目的货款总量:
>_< ?
 
  ☆提示:
select 语句 对 表 查询出来的结果 是放在内存中的缓存结果 即【结果集】。
 
where 子句 只能对 表 进行操作时起作用。无法通过 where 对 结果集 再进行筛选。
 
若希望对 结果集 进行筛选 就需要用到 having 子句。
 
 
 
(3) having 子句:
作用:★从结果集中筛选。
 
例如:
  1.查询 积压货款总量 > 20000 的栏目的货款总量:
select cat_id,sum(goods_number * shop_price) from 商品表 group by cat_id having sum(goods_number * shop_price) > 20000;
 
★也可以通过 as 对结果集中的字段 起别名,再用 having 通过 别名 对结果集进行筛选:
select cat_id,sum(goods_number * shop_price) as k from 商品表 group by cat_id having k > 20000;
 
 
  2.【经典案例】
假设 有如下表及数据:
+--------+----------+--------+
| name | subject | score |
+--------+----------+--------+
| 张三   | 数学     |    90   |
| 张三   | 语文     |    50   |
| 张三   | 地理     |    40   |
| 李四   | 语文     |    55   |
| 李四   | 政治     |    45   |
| 王五   | 政治     |    30   |
+--------+----------+---------+
要求 查询 两门及两门以上不及格者的 所有科目的平均分:
 
select name,avg(score) as pj,sum(score < 60) as gk from 表名 group by name having gk >= 2;
 
  ★难点分析:
重点是 要把‘列’当成‘变量’看待!
 
例如 当某行的 score字段 为 50 时,则 score < 60 的值 就为 1 。
反之 当某列的 score字段 为 90 时,则 score < 60 的值 就为 0 。
 
这样 sum(score < 60) 所得到的,并非不及格的成绩的总和,而是进行 关系运算 score < 60 得到的结果的总和。
 
 
 
(4) order by 子句:
作用:排序。
 
例如:
  1.取第4个栏目的商品,并且按 shop_price 字段排序:
select cat_id,goods_name,shop_price from 商品表 where cat_id = 4 order by shop_price;
  
 ★注意:
声明 asc  则升序排序,即由低到高。(默认)
声明 desc 则降序排序,即由高到低。
 
  
  2.取第4个栏目的商品,并且按 shop_price 字段降序排序:
select cat_id,goods_name,shop_price from 商品表 where cat_id = 4 order by shop_price desc;
  
  3.把不在第3个栏目的商品取出来,并且按栏目升序排序:
select cat_id,goods_name,shop_price from 商品表 where cat_id != 3 order by cat_id;
  
  4.在上例的基础上,要求 同一个栏目下的商品,按价格降序排序:
select cat_id,goods_name,shop_price from 商品表 where cat_id != 3 order by cat_id asc,shop_price desc;
 
 
(5) limit 子句:
作用:限制结果行数。
 
调用形式:
limit [偏移量,] 取出的行数
 
注意:偏移量为可选参数,其值默认为0。
 
例子:
  1.查询 本网站中 价格最高的前三个商品:
select goods_id,goods_name,shop_price from 商品表 order by shop_price desc limit 3;
 
  2.查询 本网站 价格最高的商品中 排名 第4 到 第6 的商品:
select goods_id,goods_name,shop_price from 商品表 order by shop_price desc limit 3,3;
 
 
 
五、子查询
 
  (1) where型的子查询:
where型子查询即是 把内层sql语句查询的结果 作为外层sql查询的条件。
 
☆理解 where型子查询:
 
把【子查询】的结果集 作为【主查询】的查询条件。
 
例如:
  1.查询最新的商品(goods_id最大的产品就是最新的产品):
select goods_id,goods_name,shop_price from 商品表 where goods_id = (select max(goods_id) from 商品表);
 
  2.查询 12号栏目下所有子栏目中的商品:
select cat_id,goods_name,shop_price from 商品表 where cat_id in(select cat_id from 栏目表 where parent_id = 12);
 
★注意:如上例中 使用 in 的时候,其后的 (select ...) 只能包含一个列的信息。
 
 
  (2) exists型的子查询:【exist [iɡ'zist] v.存在】
 
☆ 理解 exists型子查询:(exists型子查询相对复杂一点)
 
exists(子查询语句) ————作用:根据【子查询语句】的结果集 是 空 或 非空 返回 0 或 1 (0为假,非0为真)。
 
 
exists型子查询的实现过程如下:
 
首先 找到“主表”中的第一行记录;
 
然后 可以把该行记录中 指定字段(列)的值作为【子查询】的『查询条件』对“子表”进行查询;
 
若“子表”中存在满足『查询条件』的记录,exists()就会返回 1 ,否则返回 0 ;
 
最后【主查询】根据 exists() 的返回值 判断是否选择“主表”的该行记录。
 
接着 找到“主表”中的第二行记录 ………… 循环以上过程,直到检索完整张“主表”。
 
 
(exists型的子查询可以代替 in ,而且效率更高。但理解稍微麻烦。)
 
exists型子查询常用于查询 某个大栏目下的所有商品,例如:
 
  查询 12号栏目下所有子栏目中的商品(通过exists子查询实现):
select cat_id,goods_name,shop_price from 商品表 where exists (select * from 栏目表 where cat_id = 商品表.cat_id and parent_id = 12);
 
 
  (3) from型的子查询:
from型子查询即是 把内层sql语句查询的结果 作为临时表 提供给外层sql语句再次查询。
 
☆理解 from型子查询:
 
把【子查询】的结果集 作为一张临时表 供【主查询】再次进行查询。
 
★注意:每一个临时表必须有自己的别名。
 
例如:
  1.查询 价格最高的前3位商品,并且要求查询结果按升序排序:
select * from (select goods_id,goods_name,shop_price from 商品表 order by shop_price desc limit 3) as tmp order by shop_price;
#意思是 把 from 之后的 内层sql查询 的结果,当成临时表,别名为 tmp,供外层sql再次查询。 
 
  2.从商品表中 查询 每个栏目下最贵的商品:
方法一:
select * from 
(
select goods_id,goods_name,cat_id,shop_price from 商品表 order by shop_price desc 
) as tmp
group by cat_id;
 
方法二:
select goods_id,goods_name,cat_id,shop_price from 商品表 
where shop_price in 
(
select max(shop_price) from 商品表 group by cat_id
);
 
 
 
 
六、连接表
 
  笛卡尔乘积:
  例如:
1.通过 笛卡尔乘积 求每个商品的信息,以及其所属栏目的名称:
select * from 商品表,栏目表 where 商品表.cat_id = 栏目表.cat_id;
 
2.通过 笛卡尔乘积 求每个商品的id和名称,以及其所属栏目的id和名称:
select goods_id,goods_name,商品表.cat_id,cat_name from 商品表,栏目表 where 商品表.cat_id = 栏目表.cat_id;
 
★注意:如果两表中有重复的字段名,在使用该字段时 必须在其前面加上 表前缀(例如:goods.cat_id)。
 
以上方法是 先将两个表进行 笛卡尔乘积,得到一张“新表”,再从这张“新表”中筛选。但对两表进行 笛卡尔乘积 所得到的结果集(新表)可能会非常非常巨大。
例如:A表有 10000 行记录,B表有 10000 行记录,对 A、B表进行笛卡尔乘积 会得到 100000000 1亿行记录的结果集。所以使用这种方法开销会很大。
 
 
  左连接:
  例如:
通过 左连接 求每个商品的id和名称,以及其所属栏目的id和名称:
select goods_id,goods_name,商品表.cat_id,cat_name from 商品表 left join 栏目表 on 商品表.cat_id = 栏目表.cat_id;
 
★左连接是:以 A表(商品表) 为主,根据 条件 对 B表(栏目表) 进行有选择的连接。
            若 B表(栏目表) 中 没有满足条件的记录 则以 NULL 补齐。
 
 
  右连接:
  例如:
通过 右连接 求每个商品的id和名称,以及其所属栏目的id和名称:
select goods_id,goods_name,商品表.cat_id,cat_name from 栏目表 right join 商品表 on 商品表.cat_id = 栏目表.cat_id;
 
★右连接是:以 B表(商品表) 为主,根据 条件 对 A表(栏目表) 进行有选择的连接。
            若 A表(栏目表) 中 没有满足条件的记录 则以 NULL 补齐。
 
 
  内连接:
  例如:
通过 内连接 求有对应栏目信息的商品 的id和名称,以及其栏目的id和名称:
select goods_id,goods_name,商品表.cat_id,cat_name from 商品表 inner join 栏目表 on 商品表.cat_id = 栏目表.cat_id;
 
★内连接是:取两张表中 都满足条件 的记录 作为 一张“新表”。
            即 左连接 与 右连接 的结果集 的 交集。
 
 
★注意:MySQL 没有外连接。
 
 
  三表连接,例如:
 
1.取出第4个栏目下的商品的商品名、栏目名和品牌名:(分别有 商品表、栏目表、品牌表)
select goods_name,cat_name,brand_name 
from 商品表 left join 栏目表 on 商品表.cat_id = 栏目表.cat_id 
left join 品牌表 on 商品表.brand_id = 品牌表.brand_id 
where 商品表.cat_id = 4;
 
2.用友面试题:
根据给出的表结构按要求写出SQL语句。
 
赛程表 m
+------------+---------------+-------------------------+
| 字段名称 |  字段类型  |         描     述          |
+------------+---------------+-------------------------+
|   mid  |    int           |   主键                     |
|   hid        |    int           |   主队的ID              |
|   gid  |    int           |   客队的ID              |
|   mres     | varchar(20)|   比赛结果,如(2:0)|
|   mtime   |    date         |   比赛开始时间      |
+------------+----------------+------------------------+
 
参赛队伍表 t
+-------------+--------------+---------------+
| 字段名称 |  字段类型  |    描   述     |
+-------------+--------------+---------------+
|   tid          |    int           |  主键          |
|  tname     | varchar(20)|  队伍名称  |
+-------------+--------------+----------------+
 
m表的hid与gid都与t表中的tid关联。
 
要求查出 2006-6-1 到 2006-7-1 之间举行的所有比赛,并且用以下形式列出:
+----------+------+----------+----------------+
| hname | mres | gname |     mtime     |
+----------+------+----------+----------------+
| 国超     | 2:0  | 樱超     | 2006-05-21 |
| 樱超     | 1:2  | 横大     | 2006-06-21 |
| 横大     | 2:5  | 国超     | 2006-06-25 |
| 樱超     | 3:2  | 国超     | 2006-07-21 |
+----------+------+----------+----------------+
 
select t1.tname,mres,t2.tname,mtime
from m left join t as t1 on m.hid = t1.tid
left join t as t2 on m.gid = t2.tid
where mtime between '2006-06-01' and '2006-07-01';
 
 
 
七、union 合并结果集:
 
注意:MySQL中没有 INTERSECT 和 MINUS 只有 UNION 。
 
  ★使用 union 操作的前提:
要求两个结果集的 字段个数一致 ,字段的数据类型不相同也没关系。
 
例如:
  1.要求 在留言板页面 同时显示【用户反馈】和【用户评论】的 用户名、用户email、内容:(分别有 反馈表、评论表)
select user_name,user_email,msg_content from 反馈表
union
select user_name,email,content from 评论表;
 
  ★注意:
① 如果字段名不一致,则以第一个结果集的字段名为准。
 
② 如果两个结果集中有完全一样(即 每个字段都一样)的记录,则默认只取一行。
如果不想“内容唯一”,可以使用关键字 all 声明,例如:union all
 
  2.面试题:
a表:
+------+--------+
|   id   | num  |
+------+--------+
| a     |    5     |
| b     |   10    |
| c     |   15    |
| d     |   10    |
+------+--------+
 
b表:
+------+--------+
|   id   | num  |
+------+--------+
| b     |    5     |
| c     |   15    |
| d     |   20    |
| e     |   99    |
+------+--------+
 
要求 将a、b两表中 id 字段相同的记录 的 num 字段的内容相加,效果如下:
+------+--------------+
|   id   | sum(num) |
+------+--------------+
| a     |        5        |
| b     |       15       |
| c     |       30       |
| d     |       30       |
| e     |       99       |
+------+--------------+
 
思路:先将两表合并,再根据 id 分组,并求每组中 num 的总和。
 
select id,sum(num) from (
select * from a 
union all
select * from b
) as tmp group by id;
 
 
 

转载于:https://www.cnblogs.com/uncle-jay/p/7816336.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值