本文只是为了记录下刷sql试题的时候,所用到的一些sql函数及注意事项,知识点比较零碎,如果看官想进一步了解其用法,可能还要自行去百度一下;
#sql中关键字出现的顺序是:
select/from/where/group by/having/order by/limit
1.distinct
distinct # 得到不重复的值
2. limit
#注意:查询到的记录默认从0开始编号,而sql字符串默认从1开始编号;要注意两者的区别
select * from user limit i,n; # 从索引i处开始查找,返回n条查询结果
select * from user limit n; # 返回n条查询结果
3. between and
# 查找年龄在[20,23]之间的设备号,性别,年龄
select device_id,gender,age from user_profile where age between 20 and 23;
4. 不等号
# 不等号
select device_id,gender,age,university from user_profile where age <> "";
select device_id,gender,age,university from user_profile where university!="复旦大学";
5. 属性值为字符串的判断表示法
# 对某个属性值的字符串判断的错误写法
select device_id,gender,age,university,gpa from user_profile where gpa >3.5 and gender is "male";
# 正确写法
select device_id,gender,age,university,gpa from user_profile where gpa >3.5 and gender = "male";
6. 或 or
# 或
select device_id,gender,age,university,gpa
from user_profile
where university="北京大学" or gpa > 3.7
7. in
# in
select device_id,gender,age,university,gpa from user_profile where university in ("北京大学","复旦大学","山东大学");
8. 操作符的混合使用
# 操作符的混合使用
select device_id,gender,age,university,gpa from user_profile
where (gpa > 3.5 and university = "山东大学") or (gpa > 3.8 and university = "复旦大学");
9. like % _
# like
# %:0个或多个字符
# _:1个字符
select device_id,age,university from user_profile where university like '%北京%';
10. max
# max
select max(gpa) from user_profile where university = "复旦大学";
11. count avg
# count avg
select count(gender),avg(gpa) from user_profile where gender="male";
12. group by a,b,c...及正确的表示法
# group by a,b,c,... 可以多个属性值为一组,来进行分组,一组对应多个符合条件的值
# 注意:没有这种写法:group by (a,b,c,...)
select gender,university,count(id),avg(active_days_within_30),avg(question_cnt) from user_profile group by gender,university;
# 下面这种写法是不对的
select gender,university,count(id),avg(active_days_within_30),avg(question_cnt) from user_profile group by (gender,university);
13. having
# 分组后选取符合条件的值用having
# 取出平均发贴数低于5的学校或平均回帖数小于20的学校
select university,avg(question_cnt) as avg_question_cnt,avg(answer_cnt) as avg_answer_cnt
from user_profile
group by university
having avg_question_cnt < 5 or avg_answer_cnt < 20;
# 错误写法1 既然分组了,对分组后得到的值按要求取舍,只能用having,不能用where
select university,avg(question_cnt),avg(answer_cnt) from user_profile where avg(question_cnt) < 5 or avg(answer_cnt) < 20 group by university;
# 错误写法2 把聚合函数得到的值作为新的列名,再根据新的列名查找
select university,avg(question_cnt),avg(answer_cnt) from user_profile group by university having avg(question_cnt) < 5 or avg(answer_cnt) < 20;
14. order by
# order by 在 group by 之后
# asc 升序(默认) desc 降序
select university,avg(question_cnt) as avg_question_cnt
from user_profile
group by university
order by avg_question_cnt;
15. A left join B on 条件
# A left join B on 条件 :将属性值与A表相匹配的B表插入到A表上
select question_practice_detail.device_id,question_practice_detail.question_id,question_practice_detail.result
from question_practice_detail left join user_profile
on question_practice_detail.device_id = user_profile.device_id
where user_profile.university = "浙江大学"
order by question_practice_detail.question_id;
16. 保留小数点后n位
# 保留小数点后n为
round(x,n)
17. 统计数据表中数据的行数
# 统计表中数据的行数
count(*)
18. union all 与 union 的区别
# 将2个sql语句查询到的结果(A,B)给合并起来,结果不去重,保留重复的行
A union all B
# 比如
select device_id,gender,age,gpa from user_profile where university = "山东大学"
union all
select device_id,gender,age,gpa from user_profile where gender = "male";
# union 结果去重,不保留重复的行
19. if语句
# sql if语句
# if(condition,A,B) 如果符合条件就取值A,否则取值B
select
if(age >= 25,"25岁及以上","25岁以下") as age_cut,count(*)
from user_profile group by age_cut;
20. case语句
# case 语句
select device_id,gender,
case
when age < 20 then "20岁以下"
when age between 20 and 24 then "20-24岁"
when age >= 25 then "25岁及以上"
else "其他"
end
as age_cut
from user_profile;
21. 日期函数
# 日期
# day(date) 日期中当月的第几天
# month(date) 日期中的月份
# year(date) 日期中的年份
select day(date) as day,count(*) as question_cnt
from question_practice_detail
where month(date) = 8
group by day;
22. 日期差
# datediff(date2,date1) 日期差
23. substring_index(str,delim,count)
# substring_index(str,delim,count) 根据分隔符在字符串中的位置,来返回分隔符最左边或最右边的所有内容
# str 源字符串 delim 分隔符 count 第几个分隔符
#count > 0:从左往右数,第count个分割符的左边的所有内容
#count < 0:从右往左数,第coun个分隔符的右边的所有内容
############################
# profile:180cm,75kg,27,male
select substring_index(profile,',',-1) as gender,count(device_id) as number
from user_submit
group by gender;
24. substring(str,start,len)
# 截取字符串
substring(str,start,len) 字符串的索引编号默认从1开始 从字符串str的start位置开始,截取长度为len的字符串
25. sum与if的结合
# sum 与 if 的结合使用
sum(if(result = "right",1,0))
26. count(column) count(a,if(b_condition,true,null)) count(a_condition or null)
# count(column) 具有自动忽略空值的功能,即对column中值为空的不计数
# count(a,if(b_condition,true,null)) if中的b不能与a相同,否则会报错;这个公式根据b的值来统计a的数目
# 注意:count 与 if相结合使用的时候,空值只能用null表示,不能用0
# count(a_condition or null) 根据a的自身条件来统计
################################################
# 现在运营想要了解2021年8月份所有练习过题目的总用户数和练习过题目的总次数
select count(distinct device_id,if(result is not null,TRUE,null)) did_cnt,
count(result is not null or null) question_cnt
from question_practice_detail
where year(date) = '2021' and month(date) = '8';
27. group_concat()
# group_concat() 将分组后指定的属性值用分隔符进行连接 分隔符默认为","
# 分割符指定的时候需要加关键字 separator
select university,group_concat(distinct age separator ",") age_concat
from user_profile
group by university;
28. concat(str1,str2,....)
# 字符串拼接,str1 + str2
concat(str1,str2,...)
29. 按指定顺序返回
# 按"下旬,中旬,上旬"的顺序进行排序
order by locate(substr(dt_range,9,2),"下旬,中旬,上旬")
30. date_format(date,format) 日期的格式化
# date_format(date,format) 日期的格式化
date_format(event_date,"%Y年%m月")
31. 字符长度 字节长度
# 字符长度 char_length(str) 汉字、字母、数字都算一个字符
# 字节长度 length(str) utf8,汉字3个字节;gbk汉字2个字节
#######################################
# 注意:不能用nick_len作为where判断的条件
select device_id,nick_name,char_length(nick_name) nick_len
from user_submit
where char_length(nick_name) > 4
order by device_id desc;
32. upper(str) lower(str) 字符串大小写转换
upper(str) 转大写字母
lower(str) 转小写字母
33. trim(str) 去两边空格
trim(str) 去左右两边的空格
34. reverse(str) 反置字符串
# 反置字符串
reverse(str)
35. with as 用法
# with as 用于提前将连接操作从主函数中分离出来,以使逻辑更加清晰
# 2种写法:
# with name as (...)
# with as (...) name
with q as (select device_id,date_format(event_date,"%Y-%m") new_date,count(*) cnt
from question_practice_detail
group by device_id,date_format(event_date,"%Y-%m")
having count(*) > 1)
select distinct q1.device_id
from q q1 left join q q2 on q1.device_id = q2.device_id
# 多个别名
with name1 as (...),
name2 as (...),
name3 as (...),
...
#注意:以下这种写法不对
with name1 as (...)
with name2 as (...)
with name3 as (...)
36. left join、right join、inner join
A left join B on condition #以A表为基准,用B的信息进行填补
A right join B on condition #以B表为基准,用A的信息进行填补
A inner join B on condition #以condition为基准,取AB两表共有的
# 当多个表使用inner join的时候,要尽量把属性列多的那个表放在最左边
37.插入语句 insert into table_name values(,,,)
insert into table_name (columns1,columns2,...) values (v1,v2,...)
insert into table_name set c = v1,c = v2,...
insert into table_name select * from table_name2
# 插入语句 空值用null 自增值auto_increment用default填补
insert into table_name values (,,,) #插入的值的顺序要严格按照定义时的顺序一致
# 指定列名来插入值
insert into table_name (column_name1,column_name2,column_name3,...) values (v1,v2,v3,...)
# 或
insert into table_name set column_name1 = v1,column_name2 = v2,column_name3 = v3,....
# 将查询到的数据插入到一个表中
insert into table_name select * from table_name2 # table_name为要插入的表,table_name2为要查询的表,需保证查询出来的值要与table_name中预定义的属性值的顺序一致
# 若要将select查询到的指定数值插入
insert into new_table (column1,column2,...) select (column1,column2,...) from table where..
38. date_add(date,interval num type) 与date_sub(date,interval num type)日期间隔
# 求日期间隔
date_add(date,interval 3 day) # 在date1的基础上,增加3天
# day是间隔单位,还可取值second,minute,year,month,hour,week等
date_sub(date,interval 3 day) # 在date1的基础上,减去3天
39. insert into/insert ignore into/replace into 当插入遇到重复的键值
# 具体用法与37类似,这里只讲操作的大致原理
# 插入一行数据,若主键已存在,则会报错,否则,直接插入
insert into
# 插入一行数据,若主键已存在,则新的数据替代原来的数据(先删除再插入),否则,直接插入
replace into
# 插入一行数据,若主键已存在,则不插入,否则,直接插入
insert ignore into
40. update table_name set column1 = v1,column2 = v2... where 更新表中的某个属性值
# 更新属性值
update table_name set column1 = v1,column2 = v2... where ...
41. delete from table_name where... 删除表中的指定记录
delete from table_name where ...
42. timestampdiff(type,start,end) 求时间差,单位为type
# type取值与38类似
# end-start的单位为type的一个时间差
timestampdiff(type,start,end)
43. ifnull(exp,a)
# exp不为null,则返回exp的值,否则返回b;
# exp可以为一个条件表达式,也可以为一个字符串或数字等等
ifnull(exp,b)
44. truncate table table_name 删除记录,并重置自增键值
# 删除表中的记录并重置自增主键的索引
truncate table table_name
# 或
truncate table_name
45. 创建一个新表
create table if not exists table_name(
column_name type # 字段名,类型
primary key # 主键
foreign key # 外键
auto_increment #自增
comment "name" # 列注释
default value # 默认值
unique # 唯一约束,同列不允许有相同的值;解决表中多个字段需要唯一性约束的问题;允许多个空值
not null #非空,默认为空
) default charset = "" # 编码形式
46. 修改/删除/增加表中的字段名
alter table table_name add column column_name type # 增加字段名
alter table table_name drop column column_name type # 删除字段名
alter table table_name modify column column_name type # 修改字段类型
alter table table_name change column column_name new_column_name type # 修改字段名
# 在指定的字段名后添加一个新的字段,假如新字段名为new_column 指定的字段为specified_column
alter table table_name add new_column type after specified_column
# 注意:不管修改什么,type均不能少,否则会报错
47. 修改表名
alter table old_table_name rename to new_table_name
48. 删除表
drop table table_name
49. 创建索引
# 创建索引的基本语法
create index_mode index index_name on table_name(column_name)
# index_mode:空值 普通索引,索引值可重复
# unique 唯一索引,索引值不可重复,可有多个空值
# fulltext 全文索引,在给定的列中存储有关重要的词及位置信息,一种特殊类型的基于标记的功能性索引
50. 删除索引
# method 1
drop index index_name on table_name;
# method 2
alter table table_name drop index index_name;
51. 求当月的天数,当月有几天
last_day(date) #当月有几天
52. any_value()
MySQL提供了any_value()函数来抑制ONLY_FULL_GROUP_BY值被拒绝。
所以只需要在非group by的列上加any_value()就可以了
53. union 与 order by 的正确结合使用
# 当order by出现在union的子句中,order by会失效
# 比如:以下得到的结果并不是上表与下标都排序好,再连接到一起的;它们虽然连接到了一起,虽然各排各的,最后再连接,但并不是排序好的
# 因为order by 出现在 union的子句中,排序会失效
(select exam_id tid,count(distinct uid) uv,count(*) pv
from exam_record
group by exam_id
order by uv desc,pv desc)
union
(select question_id tid,count(distinct uid) uv,count(*) pv
from practice_record
group by question_id
order by uv desc,pv desc)
###############################################
# 要想使order by与union一起使用时,使得order by生效,那么要把order by放在union的子句的子句中
# a,b两个表名不可少
select * from
(select exam_id tid,count(distinct uid) uv,count(*) pv
from exam_record
group by exam_id
order by uv desc,pv desc)a
union
select * from
(select question_id tid,count(distinct uid) uv,count(*) pv
from practice_record
group by question_id
order by uv desc,pv desc)b
###############################################
##### 综上 #####
## 如果想要对未union前两个sql语句的查询结果进行排序,分别单独排序需要的数据,查出以后再使用union连接
select * from
( select * from t1 order by 字段 )t1 -- 一定要对表重新命名,否则报错
union select * from
( select * from t2 order by 字段 )t2
54. 左右连接时,要考虑出现重复行
# 左连接时,当右表连接到左表,当左表的一个值对应右表的多个值的时候;
# 要考虑到左表出现重复行的情况
# 当右表多个值对应左表多个值时,要考虑到连接后的左右表出现重复行的情况
# 还要考虑每个记录表中的提交时间可能会重复的情况