SQL数据查询(MySQL入门)
数据查询语言DQL也称为数据检索语句,是一种面向结构化数据的查询语言。用来在表中获取数据,确定数据怎样在应用程序给出,SQL数据查询包括单表查询和多表查询。
1. 引言
首先,回顾一下datetime数据类型,它的结构分别由year、month、day、time构成,datetime用来存储日期和时间。接下来我们就在user表中插入字段rgdata,datatime类型,非空约束。
mysql> alter table user add rgdate datetime not null;
Query OK, 0 rows affected
Records: 0 Duplicates: 0 Warnings: 0
mysql> desc user;
+-----------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------+-------------+------+-----+---------+-------+
| uid | int(20) | NO | PRI | 0 | |
| name | varchar(30) | NO | | NULL | |
| password | varchar(30) | NO | | NULL | |
| birthday | datetime | NO | | NULL | |
| telephone | varchar(30) | NO | | NULL | |
| rgdate | datetime | NO | | NULL | |
+-----------+-------------+------+-----+---------+-------+
mysql> select * from user;
+-------+--------+----------+---------------------+-------------+---------------------+
| uid | name | password | birthday | telephone | rgdate |
+-------+--------+----------+---------------------+-------------+---------------------+
| 10000 | 小文 | xiao123 | 1999-06-01 00:00:00 | 18866899966 | 2016-06-01 16:46:08 |
| 10001 | 张三 | z123456 | 1990-11-15 00:00:00 | 15286947945 | 2017-01-01 16:46:12 |
| 10002 | 李四 | lisi000 | 1989-08-24 00:00:00 | 19856245232 | 2017-04-01 16:46:15 |
| 10003 | 王麻子 | wangmazi | 1995-09-15 00:00:00 | 17932036662 | 2019-07-01 17:46:20 |
| 10004 | 大胖 | 6666666 | 1998-08-10 00:00:00 | 18782659898 | 2020-12-01 07:46:22 |
+-------+--------+----------+---------------------+-------------+---------------------+
mysql> select * from goods;
+-------+------+--------+-------+------+
| gid | code | name | price | city |
+-------+------+--------+-------+------+
| 20000 | 101 | 坚果 | 100 | 重庆 |
| 20001 | 102 | 汉服 | 200 | 上海 |
| 20002 | 103 | 空调 | 2000 | 深圳 |
| 20003 | 101 | 薯片 | 150 | 重庆 |
| 20004 | 102 | 羽绒服 | 300 | 浙江 |
| 20005 | 101 | 辣条 | 50 | 重庆 |
| 20006 | 103 | 冰箱 | NULL | 深圳 |
+-------+------+--------+-------+------+
mysql> select * from goodstype;
+------+------+
| code | type |
+------+------+
| 101 | 零食 |
| 102 | 服装 |
| 103 | 电器 |
+------+------+
mysql> select * from orders;
+-------+-------+-------+----------+
| oid | uid | gid | quantity |
+-------+-------+-------+----------+
| 30001 | 10002 | 20003 | 100 |
| 30002 | 10004 | 20000 | 10 |
| 30003 | 10002 | 20004 | 2 |
| 30004 | 10001 | 20005 | 20 |
| 30005 | 10003 | 20001 | 8 |
| 30006 | 10001 | 20002 | 1 |
| 30007 | 10002 | 20005 | 40 |
| 30008 | 10004 | 20001 | 2 |
| 30009 | 10000 | 20004 | 1 |
+-------+-------+-------+----------+
日期与时间类型,如下表:
类型 | 格式 | 字节数 | 取值范围 |
---|---|---|---|
year | yyyy | 1 | 1901~2155 |
time | hh:mm:ss | 3 | -838:59:59~838:59:59 |
date | yyyy-mm-dd | 4 | 1000-01-01~9999-12-31 |
timestamp | yyyy-mm-dd hh:mm:ss | 4 | 19700101080001~20380119111407 |
datetime | yyyy-mm-dd hh:mm:ss | 8 | 1000-01-01 00:00:00~9999-12-31 23:59:59 |
注:使用current_timestamp获取系统当前日期时间,常用于默认时间设置。 |
2. 单表查询
2.1 比较运算符
查询user表中用户uid=10002的注册时间rgdate。
mysql> select rgdate from user where uid=10002;
+---------------------+
| rgdate |
+---------------------+
| 2017-04-01 16:46:15 |
+---------------------+
查询user表中在2019年后注册的所有用户姓名name。
mysql> select name from user where year(rgdate)>=2019;
+--------+
| name |
+--------+
| 王麻子 |
| 大胖 |
+--------+
2.2 逻辑运算符
查询goods表中生产城市在重庆和商品价格为100的商品名称name。
mysql> select name from goods where city='重庆' and price='100';
+------+
| name |
+------+
| 坚果 |
+------+
查询goods表中生产城市不在重庆的商品名称name。
mysql> select name from goods where not(city='重庆');
+--------+
| name |
+--------+
| 汉服 |
| 空调 |
| 羽绒服 |
| 冰箱 |
+--------+
2.3 regexp关键字
MySQL支持正则表达式的匹配。正则表达式通常用来检索或替换符合某个模式的文本内容,根据指定的匹配模式匹配文本中符合要求的字符串。regexp常用字符匹配模式如下表:
正则表达式的模式字符 | 说明 | 示例 |
---|---|---|
^ | 匹配字符串的开始位置 | ^d:如do,dog |
$ | 匹配字符串的结束位置 | t$:如cat,test |
. | 匹配除“\n”之外的任意字符 | s.e:如she,see |
[…] | 匹配字符集合中的任意一个字符 | [12]:如100,222 |
[^…] | 匹配非字符集合中的任意一个字符 | [^123]:如456,789 |
p1|p2|p3 | 匹配p1或p2或p3 | good|bad:如good,bad |
* | 匹配零个或多个在它前面的字符 | go*d:如bad,good,等价于{0,} |
+ | 匹配前面的字符1次或多次 | vi+d:如vid,vivid,等价于{1,} |
{n} | 匹配前面的字符串至少n次,n为非负整数 | o{2}:如good,zoo |
{n,m} | 匹配前面的字符串至少n次,至多m次,m和n均为非负整数,其中n<=m | z{2,4}:如zz,zzzz |
查询user表中在2017年注册,且电话尾号为5的用户姓名name,用户年龄age。 |
mysql> select name,year(now())-year(birthday) as age from user where year(rgdate)=2017 and telephone regexp '5$';
+------+-----+
| name | age |
+------+-----+
| 张三 | 32 |
+------+-----+
注:now( )函数返回当前的日期和时间,as子句用来给字段定义别名。
2.4 like关键字
查询user表中用户姓名为“张”开头的用户信息。
mysql> select * from user where name like '张%';
+-------+------+----------+---------------------+-------------+---------------------+
| uid | name | password | birthday | telephone | rgdate |
+-------+------+----------+---------------------+-------------+---------------------+
| 10001 | 张三 | z123456 | 1990-11-15 00:00:00 | 15286947945 | 2017-01-01 16:46:12 |
+-------+------+----------+---------------------+-------------+---------------------+
查询user表中用户姓名为“王”开头,“子”结尾的用户信息。
mysql> select * from user where name like '王_子';
+-------+--------+----------+---------------------+-------------+---------------------+
| uid | name | password | birthday | telephone | rgdate |
+-------+--------+----------+---------------------+-------------+---------------------+
| 10003 | 王麻子 | wangmazi | 1995-09-15 00:00:00 | 17932036662 | 2019-07-01 17:46:20 |
+-------+--------+----------+---------------------+-------------+---------------------+
注:通配符%表示任意字符串,_表示任何单个字符;当like后的字符串不含通配符时,则可以用“=”运算符替代,而“<>”则可以替代not like运算。
2.5 in关键字
查询goods表中生产城市为重庆,上海的商品名称name。
mysql> select name from goods where city in('重庆','上海');
+------+
| name |
+------+
| 坚果 |
| 汉服 |
| 薯片 |
| 辣条 |
+------+
2.6 distinct关键字
查询goods表中商品价格大于等于100的商品在哪些城市。
mysql> select distinct city from goods where price>=100;
+------+
| city |
+------+
| 重庆 |
| 上海 |
| 深圳 |
| 浙江 |
+------+
注:当查询结果集的数据重复时,可使用distinct关键字去除重复的结果集。
2.7 is null关键字
查询goods表中商品价格为空的商品名称name。
mysql> select name from goods where price is null;
+------+
| name |
+------+
| 冰箱 |
+------+
2.8 between and关键字
查询goods表中商品价格为150到300之间的商品名称name。
mysql> select name from goods where price between 150 and 300;
+--------+
| name |
+--------+
| 汉服 |
| 薯片 |
| 羽绒服 |
+--------+
2.9 limit子句
使用limit限制结果集返回的行数。
查询goods表中第3行开始的连续4行记录的商品gid,商品编码code,商品名称name。
mysql> select gid,code,name from goods limit 2,4;
+-------+------+--------+
| gid | code | name |
+-------+------+--------+
| 20002 | 103 | 空调 |
| 20003 | 101 | 薯片 |
| 20004 | 102 | 羽绒服 |
| 20005 | 101 | 辣条 |
+-------+------+--------+
注:limit子句来指定查询结果从哪一条记录开始以及一共查询多少行记录,格式为limit [offset,] nums。参数offset表示偏移量(初始位置),参数nums表示显示记录的条数,如果偏移量为0则从查询结果的第一条记录开始。
2.10 order by子句
order by子句可以对结构集进行升序(ASC)和降序(DESC)排列,默认为升序。
查询goods表中商品编码为101的商品gid,商品名称name以及商品价格price并按照价格升序排序。
mysql> select gid,name,price from goods where code=101 order by price;
+-------+------+-------+
| gid | name | price |
+-------+------+-------+
| 20005 | 辣条 | 50 |
| 20000 | 坚果 | 100 |
| 20003 | 薯片 | 150 |
+-------+------+-------+
注:当指定的排序关键列有多个时,应分别指出各列的升序或降序选项。
2.11 group by子句
group by子句通常和聚合函数一起使用,才能实现对查询结果集进行分组和统计等操作。聚合函数有sum,avg,max,min,count,group_concat。
按照goods表中的生产城市进行分组查询。
mysql> select group_concat(name),city from goods group by city;
+--------------------+------+
| group_concat(name) | city |
+--------------------+------+
| 汉服 | 上海 |
| 羽绒服 | 浙江 |
| 空调,冰箱 | 深圳 |
| 坚果,薯片,辣条 | 重庆 |
查询每个生产城市的平均商品价格。
mysql> select avg(price) as 平均商品价格,city from goods
-> group by city;
+--------------+------+
| 平均商品价格 | city |
+--------------+------+
| 200.0000 | 上海 |
| 300.0000 | 浙江 |
| 2000.0000 | 深圳 |
| 100.0000 | 重庆 |
+--------------+------+
查询goods表中生产城市来自于重庆和深圳的商品数量并进行汇总。
mysql> select city,count(*) as 商品数量 from goods
-> where city in('重庆','深圳')
-> group by city
-> with rollup;
+------+----------+
| city | 商品数量 |
+------+----------+
| 深圳 | 2 |
| 重庆 | 3 |
| NULL | 5 |
+------+----------+
查询goods表中商量数量大于等于1的生产城市city。
mysql> select city,count(*) as 商品数量 from goods
-> group by city
-> having count(*)>=1;
+------+----------+
| city | 商品数量 |
+------+----------+
| 上海 | 1 |
| 浙江 | 1 |
| 深圳 | 2 |
| 重庆 | 3 |
+------+----------+
注:
a. group_concat( )函数必须跟group by子句一起使用;
b. group by和with rollup可以输出每一类分组的汇总值;
c. count(*)不需要任何参数,而且不能与distinct关键字一起使用;
d. having关键字和where关键字都用于设置条件表达式对查询结果集进行筛选,不同的是having关键字后可以使用聚合函数,而where关键字后不可以使用聚合函数。
3. 多表查询
3.1 连接查询(join)
3.1.1 内连接(inner join)
查询商品类型为零食的商品gid,商品名称name,商品类型type以及价格price。
mysql> select gid,name,type,price
-> from goodstype a join goods b
-> on a.code=b.code
-> where type='零食';
+-------+------+------+-------+
| gid | name | type | price |
+-------+------+------+-------+
| 20000 | 坚果 | 零食 | 100 |
| 20003 | 薯片 | 零食 | 150 |
| 20005 | 辣条 | 零食 | 50 |
+-------+------+------+-------+
3 rows in set
查询李四购买的商品名称name,商品价格price,商品数量quantity。
mysql> select b.name,price,quantity
-> from orders o join user u on o.uid=u.uid
-> join goods b on o.gid=b.gid
-> where u.name='李四';
+--------+-------+----------+
| name | price | quantity |
+--------+-------+----------+
| 薯片 | 150 | 100 |
| 羽绒服 | 300 | 2 |
| 辣条 | 50 | 40 |
+--------+-------+----------+
mysql> select b.name,price,quantity
-> from orders o join user u join goods b
-> on o.uid=u.uid and o.gid=b.gid
-> where u.name='李四';
+--------+-------+----------+
| name | price | quantity |
+--------+-------+----------+
| 薯片 | 150 | 100 |
| 羽绒服 | 300 | 2 |
| 辣条 | 50 | 40 |
+--------+-------+----------+
mysql> select goods.name,price,quantity
-> from orders join user using(uid)
-> join goods using(gid)
-> where user.name='李四';
+--------+-------+----------+
| name | price | quantity |
+--------+-------+----------+
| 薯片 | 150 | 100 |
| 羽绒服 | 300 | 2 |
| 辣条 | 50 | 40 |
+--------+-------+----------+
注:这里a,b,o,u分别是指goodstype,goods,orders,user表的别名,使用表的别名是为了防止重名,以及有些数据库表名较长而且复杂,增加代码的可读性和可维护性;在join连接中,当连接条件由两张表相同名称且类型相同的字段相连时,可以使用using(列名)来连接。
3.1.2 外连接(outer join)
左外连接(left join),结果表中除了包括满足连接条件的行外,还包括左表的所有行;右外连接(right join),结果表中除了包括满足连接条件的行外,还包括右表的所有行。
使用left join查询用户uid=10002的订单总金额ototal。
mysql> select uid,sum(price*quantity) as ototal
-> from orders o left join goods b
-> on o.gid=b.gid
-> where uid=10002;
+-------+--------+
| uid | ototal |
+-------+--------+
| 10002 | 17600 |
+-------+--------+
使用right join查询每个用户的订单数量ordernum。
mysql> select u.uid,name,count(u.uid) as ordernum
-> from user u right join orders o
-> on u.uid=o.uid
-> group by u.uid;
+-------+--------+----------+
| uid | name | ordernum |
+-------+--------+----------+
| 10000 | 小文 | 1 |
| 10001 | 张三 | 2 |
| 10002 | 李四 | 3 |
| 10003 | 王麻子 | 1 |
| 10004 | 大胖 | 2 |
+-------+--------+----------+
3.1.3 交叉连接(cross join)
使用cross join查询用户购买商品的所有可能情况。
mysql> select oid,gid,name from orders cross join user;
注:交叉连接无太多应用价值,但它可以用来为数据库生成测试数据。
3.2 联合查询(union)
使用union查询商品类型为零食和服装的商品gid,商品名称name,商品价格price,并按照商品价格升序排序,显示前4行记录。
mysql> select gid,name,price from goods join goodstype
-> on goods.code=goodstype.code
-> where type='零食'
-> union
-> select gid,name,price from goods join goodstype
-> on goods.code=goodstype.code
-> where type='服装'
-> order by price
-> limit 4;
+-------+------+-------+
| gid | name | price |
+-------+------+-------+
| 20005 | 辣条 | 50 |
| 20000 | 坚果 | 100 |
| 20003 | 薯片 | 150 |
| 20001 | 汉服 | 200 |
+-------+------+-------+
注:join可以看作是将表进行水平组合,而union则是将表进行垂直组合。
3.3 子查询(嵌套查询)
- 子查询是指在一个外层查询中包含有另一个内层查询,其中外层查询称为主查询,内层查询称为子查询。
- 子查询中可能包括in,not in,any,some,all,exists和not exists等关键字,还可能包括比较运算符。
- SQL允许多层嵌套,由内而外地进行分析,子查询的结果作为主查询的查询条件。
- 子查询的结果集也可用于插入,修改和删除数据。
- 通过子查询,实现多表之间的查询。
3.3.1 使用比较运算符的子查询
查询价格比汉服贵的商品名称name,商品价格price。
mysql> select name,price from goods where price>(select price from goods where name='汉服');
+--------+-------+
| name | price |
+--------+-------+
| 空调 | 2000 |
| 羽绒服 | 300 |
+--------+-------+
注:子查询中一般不使用order by子句,只能对最终查询结果进行排序。
3.3.2 使用in关键字的子查询
查询已购物并且订单总金额大于等于1000的用户uid,用户名称name。
mysql> select uid,name from user
-> where uid in (select uid from orders join goods using(gid) group by uid having sum(price*quantity)>1000);
+-------+--------+
| uid | name |
+-------+--------+
| 10001 | 张三 |
| 10002 | 李四 |
| 10003 | 王麻子 |
| 10004 | 大胖 |
+-------+--------+
注:int关键字同between and关键字一样用来限制查询数据的范围,not in关键字的作用与此相反。
3.3.3 使用any、some或all关键字的子查询
查询价格比服装类商品都低的商品gid,商品编码code,商品名称name和商品价格price。
mysql> select gid,code,name,price from goods
-> where price<all(select price from goods where code=(select code from goodstype where type='服装'));
+-------+------+------+-------+
| gid | code | name | price |
+-------+------+------+-------+
| 20000 | 101 | 坚果 | 100 |
| 20003 | 101 | 薯片 | 150 |
| 20005 | 101 | 辣条 | 50 |
+-------+------+------+-------+
注:all则表示外层查询的表达式要与子查询的结果集中的所有值匹配;any、some表示外层查询的表达式与子查询结果集中的值有一个匹配;any、some或all运算符必须与比较运算符一起使用。
3.3.4 使用exists关键字的子查询
如果user表中存在uid=10003的记录,则查询电话尾号为8的用户uid,用户姓名name,用户电话telephone。
mysql> select uid,name,telephone from user
-> where telephone regexp '8$' and exists(select uid from user where uid=10003);
+-------+------+-------------+
| uid | name | telephone |
+-------+------+-------------+
| 10004 | 大胖 | 18782659898 |
+-------+------+-------------+
注:使用exists关键字的子查询不需要返回任何实际数据,而仅返回一个逻辑值。如果内层查询语句查询到满足条件的记录,就返回一个真值(true),并且外层查询语句将进行查询,否则就返回一个假值(false),外层查询语句不会进行查询。not exists关键字的作用与此相反。
——>以上内容是关于SQL数据查询的基础知识,希望对初学者或再次学习者有所帮助,基础打扎实,不怕风吹雨打! 如果以上内容有错误或者内容不全,望大家提出!我也会继续写好每一篇博文!
待续未完
——文优
欢迎观看和提问!!!