select查询基础
- DQL(Data QueryLanguage):数据查询语⾔,通俗点讲就是从数据库获取数据的,按照DQL的语法给数据库发送⼀条指令,数据库将按需求返回数据
- 基本语法
select 查询的列 from 表名;
- select语句中不区分⼤⼩写,SELECT和select、FROM和from效果⼀样
- 查询的结果放在⼀个表格中,表格的第1⾏称为列头,第2⾏开始是数据,类属于⼀个⼆维数组
- 查询常量
select 常量值1,常量值2,常量值3;
- 查询表达式
select 1+2,3*10,10/3;
- 查询函数
select 函数;
,如 select mod(10,4),isnull(null),ifnull(null,'第⼀个参数为空返回这个值'),ifnull(1,'第⼀个参数为空返回这个值,否则返回第⼀个参数');
- mod函数,对两个参数取模运算
- isnull函数,判断参数是否为空,若为空返回1,否则返回0
- ifnull函数,2个参数,判断第⼀个参数是否为空,如果为空返回第2个参数的值,否则返回第1个参数的值
- 查询指定的字段
select 字段1,字段2,字段3 from 表名;
- 查询所有列
select * from 表名
,*表⽰返回表中所有字段 - 列别名:在创建数据表时,⼀般都会使⽤英⽂单词或英⽂单词缩写来设置字段名,在查询时列名都会以英⽂的形式显⽰,这样会给⽤户查看数据带来不便,这种情况可以使⽤别名来代替英⽂列名,增强阅读性
select 列 [as] 别名 from 表;
- 使⽤双引号创建别名:
select a "列1",b "列2" from test1;
- 使⽤单引号创建别名:
select a '列1',b '列2' from test1;
- 不⽤引号创建别名:
select a 列1,b 列2 from test1;
- 使⽤as创建别名:
select a as 列1,b as 列 2 from test1;
- 别名中有特殊符号的,⽐如空格,此时别名必须⽤引号引起来
- 懵逼⽰例,看效果:
-- 认真看⼀下第1个和第3个返回的结果(列头和数据),是不是懵逼状态,建议这种的最好使⽤as,as后⾯跟上别名
mysql> select 'a' 'b';
+----+
| a |
+----+
| ab |
+----+
1 row in set (0.00 sec)
mysql> select 'a' b;
+---+
| b |
+---+
| a |
+---+
1 row in set (0.00 sec)
mysql> select 'a' "b";
+----+
| a |
+----+
| ab |
+----+
1 row in set (0.00 sec)
mysql> select 'a' as "b";
+---+
| b |
+---+
| a |
+---+
- 表别名
select 别名.字段,别名.* from 表名 [as] 别名;
mysql> select t.* from test1 as t;
+---+---+
| a | b |
+---+---+
| 1 | a |
| 2 | b |
| 3 | c |
+---+---+
mysql> select * from test1 as t;
+---+---+
| a | b |
+---+---+
| 1 | a |
| 2 | b |
| 3 | c |
+---+---+
- 总结
- 建议别名前⾯跟上as关键字
- 查询数据的时候,避免使⽤select *,建议需要什么字段写什么字段
select条件查询
- 条件查询
select 列名 from 表名 where 列 运算符 值
,where后⾯跟上⼀个或者多个条件,条件是对前⾯数据的过滤,只有满⾜where后⾯条件的数据才会被返回 - 条件查询运算符
- 等于(=)
select 列名 from 表名 where 列 = 值;
- 不等于(<>、!=)
select 列名 from 表名 where 列 <> 值;
或 select 列名 from 表名 where 列 != 值;
,<> 这个是最早的⽤法,!=是后来才加上的,两者意义相同,在可移植性上前者优于后者 - ⼤于(>)
select 列名 from 表名 where 列 > 值;
,数值按照⼤⼩⽐较,字符按照ASCII码对应的值进⾏⽐较,⽐较时按照字符对应的位置⼀个字符⼀个字符的⽐较
- 逻辑查询运算符
- AND(并且)
select 列名 from 表名 where 条件1 and 条件2;
- OR(或者)
select 列名 from 表名 where 条件1 or 条件2;
- like(模糊查询)
select 列名 from 表名 where 列 like pattern;
- pattern中可以包含通配符,有以下通配符:
- %:表⽰匹配任意⼀个或多个字符
- _:表⽰匹配任意⼀个字符
- BETWEEN AND(区间查询)
selec 列名 from 表名 where 列名 between 值1 and 值2;
- 返回对应的列的值在[值1,值2]区间中的记录
- 使⽤between and可以提⾼语句的简洁度
- 两个临界值不要调换位置,只能是⼤于等于左边的值,并且⼩于等于右边的值
-- 下⾯两条sql效果⼀样
select * from stu t where t.age between 25 and 32;
select * from stu t where t.age >= 25 and t.age <= 32;
- IN查询
select 列名 from 表名 where 字段 in (值1,值2,值3,值4);
- in 后⾯括号中可以包含多个值,对应记录的字段满⾜in中任意⼀个都会被返回
- in 列表的值类型必须⼀致或兼容
- in 列表中不⽀持通配符
-- 需要查询年龄为10岁、15岁、20岁、30岁的⼈
select * from test6 t where t.age=10 or t.age=15 or t.age=20 or
t.age = 30;
select * from test6 t where t.age in (10,15,20,30);
- NOT IN查询
select 列名 from 表名 where 字段 not in (值1,值2,值3,值4);
,和列表中都不匹配的会被返回 - NULL存在的坑:查询运算符、like、between and、in、not in对NULL值查询不起效
- NULL值专⽤查询
- IS NULL(返回值为空的记录)
select 列名 from 表名 where 列 is null;
- IS NOT NULL(返回值不为空的记录)
select 列名 from 表名 where 列 is not null;
- <=>(安全等于):既可以判断NULL值,又可以判断普通的数值,可读性较低,⽤得较少
- 经典⾯试题
- 当name没有NULL值时,返回的结果⼀样
- 当name有NULL值时,第2个sql查询不出name为NULL的记录
select * from students;
select * from students where name like '%';
- 总结
- like中的%可以匹配⼀个到多个任意的字符,_可以匹配任意⼀个字符
- 空值查询需要使⽤IS NULL或者IS NOT NULL,其他查询运算符对NULL值⽆效
- 建议创建表的时候,尽量设置表的字段不能为空,给字段设置⼀个默认值
- <=>(安全等于)玩玩可以,建议少使⽤
排序和分⻚(order by 、limit)
- 排序语法
select 字段名 from 表名 order by 字段1 [asc|desc],字段2 [asc|desc];
- 需要排序的字段跟在order by之后;
- asc|desc表⽰排序的规则,asc:升序,desc:降序,默认为asc;
- ⽀持多个字段进⾏排序,多字段排序之间⽤逗号隔开。
- 按别名排序,如
select age '年龄',id as '学号' from stu order by 年龄 asc,学号 desc;
- 按函数排序,两种示例
SELECT id 编号,birth 出⽣⽇期,year(birth) 出⽣年份,name 姓名 from student ORDER BY year(birth) asc,id asc;
SELECT id 编号,birth 出⽣⽇期,year(birth) 出⽣年份,name 姓名 from student ORDER BY 出⽣年份 asc,id asc;
- year函数:属于⽇期函数,可以获取对应⽇期中的年份
- 第⼀种是在order by中使⽤了函数,第⼆种是使⽤了别名排序
- where之后进⾏排序,如
select a.id 订单编号,a.price 订单⾦额 from t_order a where a.price>=100 order by a.price desc;
- limit:⽤来限制select查询返回的⾏数,常⽤于分页等操作,
select 列 from 表 limit [offset,] count;
- offset:表⽰偏移量,通俗点讲就是跳过多少⾏,offset可以省略,默认为0,表示跳过0⾏;范围:[0,+∞)
- count:跳过offset⾏之后开始取数据,取count⾏记录;范围:[0,+∞)
- limit中offset和count的值不能⽤表达式
- 获取最⼤的⼀条记录:先降序,然后取第⼀条记录
select a.id 订单编号,a.price 订单⾦额 from t_order a order by a.price desc limit 1;
- 获取排名第n到m的记录:我们需要先跳过n-1条记录,然后取m-n+1条记录
- 分⻚查询:
select 列 from 表名 limit (page - 1) * pageSize,pageSize;
- limit注意事项
- 不能使⽤表达式,后⾯只能够跟明确的数字
- 后⾯的2个数字不能为负数
- 总结
- order by … [asc|desc]⽤于对查询结果排序,asc:升序,desc:降序,asc|desc可以省
略,默认为asc - limit⽤来限制查询结果返回的⾏数,有2个参数(offset,count),offset:表⽰跳过
多少⾏,count:表⽰跳过offset⾏之后取count⾏ - limit中offset可以省略,默认值为0
- limit中offset 和 count都必须⼤于等于0
- limit中offset和count的值不能⽤表达式
- 分页排序时,排序不要有⼆义性,⼆义性情况下可能会导致分页结果乱序,可以在后⾯追加⼀个主键排序
分组查询(group by、having)
- 分组查询
- group_function:聚合函数
- groupbyexpression:分组表达式,多个之间⽤逗号隔开
- group_condition:分组之后对数据进⾏过滤
- 分组中,select后⾯只能有两种类型的列:出现在group by后的列;或者使⽤聚合函数的列
SELECT column, group_function,... FROM table
[WHERE condition]
GROUP BY group_by_expression
[HAVING group_condition];
- 聚合函数
- max 查询指定列的最大值
- min 查询指定列的最小值
- count 统计查询结果的行数
- sum 求和,返回指定列的总和
- avg 求平均值,返回指定列数据的平均值
- 单字段分组,如
SELECT
user_id ⽤户id, COUNT(id) 下单数量
FROM
t_order
GROUP BY user_id;
SELECT
user_id ⽤户id, the_year 年份, COUNT(id) 下单数量
FROM
t_order
GROUP BY user_id, the_year;
SELECT
user_id ⽤户id, COUNT(id) 下单数量
FROM
t_order t
WHERE
t.the_year = 2018
GROUP BY user_id;
SELECT
user_id ⽤户id, COUNT(id) 下单数量
FROM
t_order t
WHERE
t.the_year = 2018
GROUP BY user_id
HAVING count(id)>=2;
-- 或
SELECT
user_id ⽤户id, count(id) 下单数量
FROM
t_order t
WHERE
t.the_year = 2018
GROUP BY user_id
HAVING 下单数量>=2;
- where和having的区别
- where是在分组(聚合)前对记录进⾏筛选,⽽having是在分组结束后的结果⾥筛选,最后返回整个sql的查询结果
- 可以把having理解为两级查询,即含having的查询操作先获得不含having⼦句时的sql查询结果表,然后在这个结果表上使⽤having条件筛选出符合的记录,最后返回这些记录,因此,having后是可以跟聚合函数的,并且这个聚集函数不必与select后⾯的聚集函数相同
- 分组后排序
SELECT
user_id ⽤户id, max(price) 最⼤⾦额
FROM
t_order t
GROUP BY user_id
ORDER BY 最⼤⾦额 desc;
- where & group by & having & order by & limit ⼀起协作,先后顺序有明确的限制
select 列 from
表名
where [查询条件]
group by [分组表达式]
having [分组过滤条件]
order by [排序条件]
limit [offset,] count;
-- 比如:
SELECT
user_id ⽤户id, COUNT(id) 下单数量
FROM
t_order t
WHERE
t.the_year = 2018
GROUP BY user_id
HAVING count(id)>=2
ORDER BY 下单数量 DESC
LIMIT 1;
- mysql分组中的坑
- 分组中select后⾯的列只能有2种:出现在group by后⾯的列,使⽤聚合函数的列
- 建议在写分组查询的时候,最好按照标准的规范来写,select后⾯出现的列必须在group by中或者必须使⽤聚合函数
-- 获取每个⽤户下单的最⼤⾦额及下单的年份,输出:⽤户id,最⼤⾦额,年份
-- 错误示例,the_year不符合上⾯说的2条规则
select user_id ⽤户id, max(price) 最⼤⾦额, the_year 年份
FROM t_order t
GROUP BY t.user_id;
-- ⽐较少见,in中使⽤了多字段查询
SELECT user_id ⽤户id, price 最⼤⾦额, the_year 年份
FROM t_order t1
WHERE (t1.user_id , t1.price) IN
(SELECT t.user_id, MAX(t.price)
FROM t_order t
GROUP BY t.user_id);
SELECT user_id ⽤户id, price 最⼤⾦额, the_year 年份
FROM t_order t1,
(SELECT t.user_id uid, MAX(t.price) pc
FROM t_order t
GROUP BY t.user_id) t2
WHERE t1.user_id = t2.uid AND t1.price = t2.pc;
- 总结
- 在写分组查询的时候,最好按照标准的规范来写,select后⾯出现的列必须在group by中或者必须使⽤聚合函数
- select语法顺序:select、from、where、group by、having、order by、limit,顺序不能搞错了,否则报错
- in多列查询的使⽤,下去可以试试