第5章 排序检索数据
关系型数据库设计理论认为,如果不明确规定排序顺序,则不应该假定检索出的数据的顺序有意义
5.1使用order by 子句对输出排序
# 按单列排序
select prod_name from products # 不排序
select prod_name from products order by prod_name; # 以字母顺序排序prod_name列
select prod_name from products order by prod_id; # 使用非检索的列排序数据也是合法的,如使用prod_id顺序排列prod_name
使用非检索的列排序数据也是合法的,如使用prod_id顺序排列prod_name。选择的是prod_name数据,按照prod_id排序。但是你筛选的结果在直观上是不太直观的排序的。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-G5PNmkkK-1611933180130)(C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20210129065340039.png)]
上图有些数据就不是排序的,因为排序规则不是按照本身,而是按照prod_id。
# 按多列排序
select prod_id, prod_price,prod_name from products order by prod_price, prod_name; #选择三列数据,先按价格,再按产品名排序
他是说,prod_price中的两个2.50的数据,再按照prod_name进行排序。
对prod_price中相同的数据,再按照prod_name进行排序。
# 降序排列 desc,desc 只作用于直接位于其前面的列名。这个和淘宝上的搜索筛选有些相似。
# decrease=降序排列 desc
# ascending=升序排序 asc
select prod_id, prod_price,prod_name from products order by prod_price desc; # 按价格降序排列
select prod_id, prod_price,prod_name from products order by prod_price desc, prod_name; #先按价格降序排列,再按产品名升序排列
select prod_id, prod_price,prod_name from products order by prod_price desc, prod_name desc; #先按价格降序排列,再按产品名降序排列
order by prod_price desc, prod_name desc :这里两个排序规则,先用价格,再用名称,使用了两个desc,是因为desc只作用于直接位于其前面的列名。
也就是每一列都必须指定desc关键字
# 使用order by 和limit组合,找出一列中最高或最低的值
# 顺序:order by子句必须在from子句之后,limit子句必须在order by之后
select prod_price from products order by prod_price desc limit 1; # 最高值
select prod_price from products order by prod_price desc limit 3; # 选择出价格较高的三种产品的价格。
select prod_price from products order by prod_price limit 1; # 最低值
select prod_price from products order by prod_price asc limit 1; # 最低值
SELECT prod_name,prod_price FROM products ORDER BY prod_price DESC LIMIT 5; # 选择出价格较高的三种产品的产品名称。我觉得这个才符合业务上的要求吧
第6章 过滤数据
6.1where
select prod_name,prod_price from products where prod_price = 2.50; # 价格等于2.50的产品名、产品价格
SELECT * FROM products WHERE prod_price = 2.50; # 价格等于2.50的产品的所有信息
6.2where
# Mysql在执行语句时,不区分大小写。"fuses"="Fuses"="Fuses"。另外‘’=“”
SELECT prod_name,prod_price FROM products WHERE prod_name="fuses"
SELECT prod_name,prod_price FROM products WHERE prod_name="Fuses"
SELECT prod_name,prod_price FROM products WHERE prod_name="Fuses"
select prod_name,prod_price from products where prod_price < 10; # 价格小于10的产品名、产品价格
select prod_name,prod_price from products where prod_price <=10; # 价格小于等于10的产品名、产品价格
SELECT prod_name,prod_price FROM products WHERE prod_price <=10 ORDER BY prod_price; # 价格小于等于10的产品名、产品价格。我觉得结果再加上排序才会好看,有价值。
我觉得结果再加上排序才会好看,有价值。
6.2.2不匹配检查
不等于,!=,<>。
SELECT * FROM products WHERE prod_name!="fuses" ORDER BY vend_id; # 选择不是fuses的其他产品的信息。
SELECT * FROM products WHERE prod_name<>"fuses" ORDER BY vend_id; # 选择不是fuses的其他产品的信息。
6.2.3范围值检索,between A and B,包括A和B
# 选择价格区间,between 5 and 10 :价格大于等于5,小于等于10
SELECT * FROM products WHERE prod_price BETWEEN 5 AND 10 ORDER BY prod_name; # 选择价格区间
6.2.4空值检查
select prod_name from products where prod_price is null; # 返回prod_price为空值null的prod_name,无对应数据
select cust_id from customers where cust_email is null; # 检索cust_email为空值时的cust_id
/*
下面的句子不太理解:
在通过过滤选择出不具有特定值的行时,你可能希望返回具有NULL值得行。
但是,不行。因为未知具有特殊的含义,数据库不知道他们是否匹配,所以在匹配过滤和不匹配过滤中不返回NULL。
因此,在过滤数据时,一定要验证返回数据中确实给出了被过滤列具有NULL的行。
*/
select * from customers where cust_email is null; # 检索cust_email为空值时的 消费者数据
第7章 数据过滤
7.1and 或 or 操作符连接多个where子句
7.1.1AND 用在WHERE子句中的关键字,用来指示检索满足所有给定条件的行
-- select * 岂不是更快的写出了语句,当然有些结果不需要。
select vend_id,prod_price,prod_name from products
where vend_id = 1003 and prod_price <= 10; #检索由供应商1003制造且价格小于等于10美元的产品信息
-- 完整的数据表里,一个供应商可以提供多种产品。
7.1.2OR操作符,指示MySQL检索匹配任一条件的行
SELECT vend_id,prod_name,prod_price FROM products
WHERE vend_id = 1002 OR vend_id = 1003
ORDER BY vend_id; # 检索由任一个指定供应商制造的所有产品的产品信息
7.1.3and 和 or结合,and优先计算
使用圆括号可以明确操作,消除歧义,保证计算顺序。
-- 优先计算and,查找vend_id为1003且价格>=10的产品,或者vend_id为1002的产品,不管vend_id为1002的产品的价格如何
-- 这个案例提示and 和 or结合,and优先计算。需要外加括号保证正确的计算和结果
select vend_id,prod_name,prod_price from products
where vend_id = 1002 or vend_id = 1003 and prod_price >= 10
ORDER BY vend_id;
-- 使用圆括号明确运算顺序:查找vend_id为1002或1003,且价格>=10的产品
-- 下图没有id=1002的供应商的信息,因为从上图可知,id=1002的供应商的产品价格均不满足 prod_price >= 10
select vend_id,prod_name,prod_price from products
where (vend_id = 1002 or vend_id = 1003) and prod_price >= 10
ORDER BY vend_id;
7.2IN操作符
我觉得,between是对数据的,in是对列表的操作,in操作符完成与OR相同的功能。
# IN操作符后跟由逗号分隔的合法值清单,整个清单必须括在圆括号
SELECT vend_id,prod_name,prod_price FROM products
WHERE vend_id IN (1002,1003) ORDER BY vend_id;
# IN操作符完成与OR相同的功能
select vend_id,prod_name,prod_price from products
where vend_id = 1002 or vend_id = 1003 order by vend_id; # 同上
7.3NOT操作符
not 和 in 在一起使用。not in。
Mysql支持not对in,between,exsits子句取反 。
# 列出1002和1003之外的供应商生产的产品
select vend_id,prod_name,prod_price from products
where vend_id not in (1002,1003) order by prod_name;
# Mysql支持not对in,between,exsits子句取反
# EXISTS用于检查子查询是否至少会返回一行数据,该子查询实际上并不返回任何数据,而是返回值True或False
# EXISTS 指定一个子查询,检测 行 的存在。
没有例子,额不会
第8章 用通配符进行过滤
%,_,
/*
通配符:用来匹配值得一部分的特殊字符
搜索模式:由字面值、通配符或两者组合构成的搜索条件
Like操作符:为在搜索子句中使用通配符,必须使用like操作符。
指示mysql,其后跟的搜索模式利用通配符匹配而不是直接相等匹配进行比较。
*/
-- 通配符类型
8.1.1百分号 % 通配符 :表示任何字符(包括0个字符 )出现任意次数
特殊:注意 % 不能匹配NULL空值!
8.1.1找到所有以词jet起头的产品
select prod_id,prod_name from products where prod_name like "jet%";
通配符可以在搜索模式任意位置使用
# 比如下方出现在头尾两处 ,匹配任意位置包含文本anvil的值
select prod_id,prod_name from products where prod_name like "%anvil%";
# 比如下方出现在搜索模式的中间,匹配所有以s开头e结尾的值
select prod_name from products where prod_name like "s%e";
8.1.2下划线 _ 通配符 :匹配一个字符,不能多不能少
通配符与内容之间加上空格。
select prod_id,prod_name from products
where prod_name like "% ton anvil";
select prod_id,prod_name from products
where prod_name like "_ ton anvil";
SELECT prod_id,prod_name FROM products
WHERE prod_name LIKE "__ ton anvil"; -- 这里是两个下划线,匹配了两个字符。返回结果是.5 ton anvil
技巧:把通配符至于搜索模式的开始处,搜索起来是最慢的!
第9章 用正则表达式进行搜索
– 基本字符匹配 RegExp(正则表达式)
regexp “1000” = 包含’1000’
# 查找产品名中含有'1000'的所有行
select prod_name from products where prod_name regexp "1000";
select prod_name from products where prod_name regexp ".000";# .在正则表达式中,匹配任意 一个 字符
-- like 和 正则表达式的区别 ,是否在列值中匹配
-- like在整个列中查找,如果被匹配的文本出现在列值中,匹配不到结果,除非使用通配符
-- 没有prod_name完全相等于1000的数据。
select prod_name from products where prod_name like "1000" order by prod_name; -- 无返回结果
# like + 通配符
select prod_name from products where prod_name like "%1000" order by prod_name; # 返回结果'JetPack 1000'
select prod_name from products where prod_name like "%000" order by prod_name; # 返回结果 'JetPack 1000' 'JetPack 2000'
# Regexp在列值中匹配
select prod_name from products where prod_name regexp ".000" order by prod_name; # 返回结果 'JetPack 1000' 'JetPack 2000'
-- regexp如何匹配整个列,同like效果呢,使用^和$定位符即可
-- 见后文
-- 正则表达式匹配默认不分大小写,需使用BINARY区分大小写
select prod_name from products where prod_name regexp "JetPack .000";
select prod_name from products where prod_name regexp binary "JetPack .000";
9.2.2 or |
-- 正则表达式的OR操作符: |
-- 和in有点相似啊。
select prod_name from products where prod_name regexp "1000|2000" order by prod_name;-- 没有结果
select prod_name from products where prod_name in (JetPack 1000,JetPack 2000) order by prod_name;-- 错误,不能执行
SELECT prod_name FROM products WHERE prod_name IN ('JetPack 1000','JetPack 2000') ORDER BY prod_name; -- 这样才可以运行
select prod_name from products where prod_name in (1000,2000) order by prod_name;
9.2.3正则表达式匹配几个字符之一 [ ]
-- 正则表达式匹配几个字符之一 [ ]
select prod_name from products where prod_name regexp '[123] Ton' order by prod_name; # [123]匹配单一字符:1或2或3
select prod_name from products where prod_name regexp '[1|2|3] Ton' order by prod_name; # [1|2|3]同[123],匹配单一字符:1或2或3
select prod_name from products where prod_name regexp '1|2|3 ton' order by prod_name; # '1|2|3 ton'匹配1或2或'3 ton'
select prod_name from products where prod_name regexp '[^123]' order by prod_name; # 取反
SELECT prod_name FROM products WHERE prod_name REGEXP 'Ton' ORDER BY prod_name; # [123]匹配单一字符:1或2或3
SELECT prod_name FROM products WHERE prod_name REGEXP '[123]Ton' ORDER BY prod_name; # 错误。[123]和Ton之间需要加上空格。
SELECT prod_name FROM products WHERE prod_name REGEXP '[123] Ton' ORDER BY prod_name; # [123]匹配单一字符:1或2或3
9.2.4匹配范围
-- 正则表达式匹配范围
select prod_name from products where prod_name regexp '[1-5] Ton' order by prod_name; # [1-5]匹配1,2,3,4,5。Ton=ton不区分大小写。
这里需要加上空格。 。因为数据表中也有空格。
SELECT prod_name FROM products WHERE prod_name REGEXP '[a-z]afe' --不区分大小写
SELECT prod_name FROM products WHERE prod_name REGEXP '[A-Z]afe' --不区分大小写
-- [a-z]和[A-Z]结果相同。
SELECT prod_name FROM products WHERE prod_name REGEXP '[A-Z] afe' --这个没有返回结果,因为多了一个空格。
9.2.5匹配特殊字符
-- 正则表达式匹配特殊字符,必须用\\前导,进行转义
-- 多数正则使用单反斜杠转义,但mysql使用双反斜杠,mysql自己解释一个,正则表达式库解释一个
select vend_name from vendors where vend_name regexp "\\." order by vend_name; # ‘\\.'匹配字符.
select vend_name from vendors where vend_name regexp "." order by vend_name; # '.'匹配任意字符,每行都会被检索出来,输出全部数据。
9.2.6正则表达式匹配字符类
# [:alnum:] 任意字母和数字(同[a-zA-Z0-9])
# [:alpha:] 任意字符(同[a-zA-Z])
# [:blank:] 空格和制表(同[\\t])
# [:cntrl:] ASCII控制字符(ASCII 0到31和127)
# [:digit:] 任意数字(同[0-9])
# [:graph:] 与[:print:]相同,但不包括空格
# [:lower:] 任意小写字母(同[a-z])
# [:print:] 任意可打印字符
# [:punct:] 既不在[:alnum:]又不在[:cntrl:]中的任意字符
# [:space:] 包括空格在内的任意空白字符(同[\\f\\n\\r\\t\\v])
# [:upper:] 任意大写字母(同[A-Z])
# [:xdigit:] 任意十六进制数字(同[a-fA-F0-9])
select prod_name from products where prod_name regexp '[:digit:]' order by prod_name; #[:digit:]匹配任意数字
[[:alnum:]] 需要加两个[ ]才可以。
SELECT prod_name FROM products WHERE prod_name REGEXP '[[:alnum:]] ton' -- 需要加两个[ ]才可以。
SELECT prod_name FROM products WHERE prod_name REGEXP '. ton'
SELECT prod_name FROM products WHERE prod_name REGEXP '_ ton'
9.2.7匹配多个实例 {}重复元字符
# * 0个或多个匹配
# + 1个或多个匹配(等于{1,})
# ? 0个或1个匹配(等于{0,1})
# {n} 指定数目的匹配
# {n,} 不少于指定数目的匹配
# {n,m} 匹配数目的范围(m不超过255)
select prod_name from products where prod_name regexp '\\([0-9] sticks?\\)'
order by prod_name; # 返回了'TNT (1 stick)'和'TNT (5 sticks)'
select prod_name from products where prod_name regexp '[[:digit:]]{4}'
order by prod_name; # [[:digit:]]{4} --匹配连在一起的任意4位数字。表示四位数字。
9.2.8定位符,为了 避免在文本内的任意位置查找匹配
# ^ 文本的开始
# $ 文本的结尾
# [[:<:]] 词的开始
# [[:>:]] 词的结尾
文本和词一样吗???
select prod_name from products where prod_name regexp '^[0-9\\.]' order by prod_name; #找出以一个数(包括以小数点开始的数)开始的所有产品
select prod_name from products where prod_name regexp '[0-9\\.]' order by prod_name; #找出包括小数点和数字的所有产品
包括=包含。
-- ^的双重作用
# 在集合中(用[和]定义),用它来否定该集合
# 用来指串的开始处
上面的点,我给忘记了。。。等再看的时候再说吧。。。
-- 不使用数据库表进行正则表达式的测试:匹配返回1,无匹配返回0
select 'hello' regexp '[0-9]'; # 返回 0
select 'hello' regexp '[:alnum:]'; # 返回 1。alnum是指字母和数字。
第10章 创建计算字段
计算字段,也就是将选择出来的数据进行格式化显示。
10.2拼接字段 concat()
-- 拼接字段 concat()
select concat(vend_name,' (',vend_country,')') from vendors order by vend_name; -- 格式化输出
SELECT CONCAT('供应商:',vend_name,'位置:',vend_country) FROM vendors ORDER BY vend_name; -- 格式化输出
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dgrEAnRO-1611933180241)(https://gitee.com/xingchen1968/cloud-image2/raw/master/img/image-20210129210321499.png)]
SELECT CONCAT('供应商:',vend_name,'----位置:',vend_country) FROM vendors ORDER BY vend_name; -- 格式化输出。自己格式化一下。
-- trim()和java中很相似啦。力扣的一道题目。
-- 删除数据左侧多余空格 ltrim()
-- 删除数据两侧多余空格 trim()
-- 删除数据右侧多余空格 rtrim()
SELECT CONCAT(RTRIM(vend_name),' (',RTRIM(vend_country),')') FROM vendors ORDER BY vend_name;
SELECT CONCAT(RTRIM(vend_name),' (',vend_country,')') FROM vendors ORDER BY vend_name;
SELECT CONCAT('供应商:',vend_name,'----位置:',vend_country) FROM vendors ORDER BY vend_name; -- 格式化输出。自己格式化一下。
SELECT CONCAT('供应商:',vend_name,'----位置:',trim(vend_country)) FROM vendors ORDER BY vend_name; -- 格式化输出。自己格式化一下。
没感觉到差别。
10.2.2-- as赋予别名
-- as赋予别名
select concat(rtrim(vend_name),' (',rtrim(vend_country),')') as '我的名字' from vendors order by vend_name;
也就是说,把名字更改了,计算字段的名字原来是代码,现在用as可以任意修改别名了。
实际存在,我没找到存在哪里了。可能这里的实际存在是说在输出列表上。
10.3-- 执行算数计算
-- 执行算数计算
select prod_id,quantity,item_price from orderitems where order_num = 20005;
select prod_id,quantity,item_price,quantity * item_price as expanded_price
from orderitems where order_num = 20005; # 计算总价expanded_price
没有as别名,那就是计算字段。
-- 简单测试计算
select 2*3; --6
select trim('abc');
select now(); # 返回当前日期和时间
SELECT (' abc '),TRIM(' abc ');
第11章 利用数据处理函数
– 文本处理函数
left() -- 返回串左边的字符
length() -- 返回串的长度
locate() -- 找出串的一个子串
lower() -- 将串转换为小写
ltrim() -- 去掉串左边的空格
right() -- 返回串右边的字符
rtrim() -- 去掉串右边的空格
soundex() -- 返回串的soundex值。类似的发音字符和字节。发音类似。
substring() -- 返回子串的字符
upper() -- 将串转换为大写
-- UPPER()函数 转换文本为大写
select vend_name, upper(vend_name) as '转大写'from vendors order by vend_name;
-- soundex() 描述语音表示的字母数字模式的算法,对串按照发音比较而不是字母比较
-- 选择cust_contact中和Y. Lie发音相似的数据。
select cust_name,cust_contact from customers where cust_contact = 'Y. Lie'; -- 无返回
select cust_name,cust_contact from customers where soundex(cust_contact) = soundex('Y. Lie'); -- 按发音搜索
11.2.2日期和时间处理函数
– 日期和时间处理函数,描述订单下单的日期和时间。
# adddate() 增加一个日期(天,周等)
# addtime() 增加一个时间(时、分等)
# curdate() 返回当前日期
# curtime() 返回当前时间
# date() 返回日期时间的日期部分
# datediff() 计算两个日期之差
# date_add() 高度灵活的日期运算函数
# date_format() 返回一个格式化的日期或时间串
# day() 返回一个日期的天数部分
# dayofweek() 对于一个日期,返回对应的星期几
# hour() 返回一个时间的小时部分
# minute() 返回一个时间的分钟部分
# month() 返回一个日期的月份部分
# now() 返回当前日期和事件
# second() 返回一个时间的秒部分
# time() 返回一个日期时间的时间部分
# year() 返回一个日期的年份部分
# 首选的日期格式yyyy-mm-dd,避免多义性
SELECT order_date,cust_id,order_num FROM orders WHERE order_date = "2005-09-01";
select * from orders; # order_date为datetime数据类型,含有时间信息;如果时间信息不是00:00:00,上句查找无结果。应该是返回所有数据吧。
orders他本身就只有下面的这些数据呀。
-- 按照date()日期进行过滤信息,更可靠
select cust_id,order_num from orders where date(order_date) = "2005-09-01";
select cust_id,order_num from orders where date(order_date) = "2005";--无结果,是日期,而不是年啊
SELECT cust_id,order_num,order_date FROM orders WHERE YEAR(order_date) = "2005";
# 检索2005年9月下的订单
SELECT cust_id,order_num,order_date FROM orders WHERE YEAR(order_date) = 2005 AND MONTH(order_date) = 9;
select cust_id,order_num,order_date from orders where date(order_date) between "2005-09-01" and "2005-09-30";
.-- 数值处理函数
# abs() 返回一个数的绝对值
# cos() 返回一个角度的余弦
# exp() 返回一个数的指数值
# mod() 返回除操作的余数
# pi() 返回圆周率
# sin() 返回一个角度的正弦
# sqrt() 返回一个数的平方根
# tan() 返回一个角度的正切
SELECT PI(),结果是3.14156
SELECT TAN(45/180),SELECT TAN(45),都没有得到理想结果。tan(45)=1。
第12章 汇总数据
12.1聚类函数
# avg() 返回某列的平均值
# count() 返回某列的行数。也就是数据的个数。
# max() 返回某列的最大值
# min() 返回某列的最小值
# sum() 返回某列值之和
12.1.1avg()
-- avg()
# AVG()返回products表中所有产品的平均价格。所有产品的平均价格。所有产品的平均价格。所有产品的平均价格。所有产品的平均价格。
select avg(prod_price) as avg_price from products;--和excel的功能类似。但是要强大一些。
# 返回特定供应商所提供产品的平均价格
select avg(prod_price) as avg_price from products where vend_id = 1003; -- where 限定条件。
# avg()只能作用于单列,多列使用多个avg()
select avg(item_price) as avg_itemprice,avg(quantity) as avg_quantity from orderitems; -- as用来重命名。
-- count()
# COUNT(*)对表中行的数目进行计数,不忽略空值,所有数据都被计入。忽略空值的意思是null的数据不被计入。
select count(*) as num_cust from customers;
select count(cust_email) as cust_email from customers;
# 使用COUNT(column)对特定列中具有值的行进行计数,忽略NULL值
select count(cust_email) as cust_email from customers;
email,个数为3。count(*)不忽略空值。count(具体的列名)会忽略空值。
忽略空值的意思是null的数据不被计入。
12.1.3max()
-- max() & min()
# MAX()返回products表中最贵的物品的价格
select max(prod_price) as max_price from products;
# 在用于文本数据时,如果数据按相应的列排序,则MAX()返回最后一行
select max(prod_name) from products;
12.1.4min()
# MIN()返回products表中最便宜物品的价格
select min(prod_price) as min_price from products;
# 在用于文本数据时,如果数据按相应的列排序,则MIN()返回最前面一行
select min(prod_name) from products; --不适合文本。只适合数值型的数据。
12.1.5sum()
# 检索所订购物品的总数(所有quantity值之和)
select sum(quantity) as items_ordered from orderitems;
select sum(quantity) as items_ordered from orderitems where order_num = 20005;
# 订单20005的总订单金额
select sum(quantity * item_price) as total_price from orderitems where order_num = 20005;
select sum(quantity * item_price) as total_price from orderitems;
12.2聚类不同值 distinct
DISTINCT参数,只考虑各个不同的价格。distinct本意就是不同的。font>
# 使用了DISTINCT参数,因此平均值只考虑各个不同的价格
select avg(distinct prod_price) as avg_price from products where vend_id = 1003;
# distinct 只能作用于count(),不能用于count(*)
# distinct 同max(),min()的结合使用,没有意义
– 组合聚类函数
# 4个聚集计算:物品的数目,产品价格的最高、最低以及平均值
SELECT
COUNT(*) AS num_items,
MIN(prod_price) AS price_min,
MAX(prod_price) AS price_max,
AVG(prod_price) AS price_avg
FROM
products;