1、对视图的理解
《sql基础教程**第2版》用一句话非常凝练的概括了视图与表的区别—“是否保存了实际的数据”。所以视图并不是数据库真实存储的数据表,它可以看作是一个窗口,通过这个窗口我们可以看到数据库表中真实存在的数据。所以我们要区别视图和数据表的本质,即视图是基于真实表的一张虚拟的表,其数据来源均建立在真实表的基础上。
那既然已经有数据表了,为什么还需要视图呢?主要有以下几点原因:
通过定义视图可以将频繁使用的SELECT语句保存以提高效率。
通过定义视图可以使用户看到的数据更加清晰。
通过定义视图可以不对外公开数据表全部字段,增强数据的保密性。
通过定义视图可以降低数据的冗余。
视图不仅可以基于真实表,我们也可以在视图的基础上继续创建视图。
虽然在视图上继续创建视图的语法没有错误,但是我们还是应该尽量避免这种操作。这是因为对多数 DBMS 来说, 多重视图会降低 SQL 的性能。
2、视图的更改会直接改原始表的数据,因为视图本身是原始表的一个窗口而已。
3、学会利用标量子查询:
标量子查询的意思是返回一个值。例如
select avg(product_name) from product
标量子查询的使用场景:
查询出销售单价高于平均销售单价的商品
select product_id, product_name, sale_price
from product
where sale_price > (select avg(sale_price) from product)
由于标量子查询的特性,导致标量子查询不仅仅局限于 WHERE 子句中,通常任何可以使用单一值的位置都可以使用。也就是说, 能够使用常数或者列名的地方,无论是 SELECT 子句、GROUP BY 子句、HAVING 子句,还是 ORDER BY 子句,几乎所有的地方都可以使用。
4、关于关联子查询,这个知识点必须要真的理解才知道怎么操作的,这个博客写的很好https://zhuanlan.zhihu.com/p/41844742,我自己的理解是,它主要是类似一个FOR循环,先执行的是主查询,之后看关联语句,把关联语句的第一个值传入子查询,对子查询进行执行,并返回相应的结果到主查询;把关联语句的第二个值传入子查询,对子查询进行执行,并返回相应的结果到主查询;以此类推,进行for循环。
选取出各商品种类中高于该商品种类的平均销售单价的商品。
SELECT product_type, product_name, sale_price
FROM product AS p1
WHERE sale_price > (SELECT AVG(sale_price)
FROM product AS p2
WHERE p1.product_type = p2.product_type
GROUP BY product_type);
但是,我以往的做法都是join两个表,之后再一个嵌套select出来。也不是不可以,但是感觉没有像上面那个语法简单。
练习:
NO1
create VIEW ViewPractice5_1(product_name, sale_price, regist_date)
as
select product_name, sale_price, regist_date
from product
where sale_price >= 1000 and regist_date = '2009-09-20';
NO2:
看下执行结果:
原因是:造成该问题的原因是: 当向视图中插入数据时,同时也会向原表插入数据插入数据 ,而原表中存在多个字段不允许为空,所以无法插入。
我们把NOT NULL的字段填上
create or replace View ViewPractice5_2(product_name, sale_price, regist_date, product_id, product_type)
as
select product_name, sale_price, regist_date,product_id, product_type
from product
where sale_price >= 1000 and regist_date = '2009-09-20';
insert into ViewPractice5_2 values (' 刀子 ', 300, '2009-11-02',100, '办公用品');
select * from ViewPractice5_2;
结果是insert 成功了,但是视图却没有改变,WHY?
答案是对视图的操作其实是对原始表的操作Insert是到原始表了,但是由于我们视图创建时有一个条件是where sale_price >= 1000 and regist_date = '2009-09-20';所以,在view里是看不到新插入的数据的,在原始表里才能看到!!
看看原始表的情况:
NICE! 和预计的一样!
NO3
这里先有个小tips,由于我做了上一题,插入了一行数据,我先要用delete from table where product_id = 100删除这一行,结果出现了这个情况:
一番搜索之后发现原来是MySQL Workbench的安全设置。当要执行的SQL语句是进行批量更新或者删除的时候就会提示这个错误。
解决方法是:
改完之后需要重启一下,才能生效。
好嘞,下面开始做这个题:
考点是【对标量子查询的理解】
select product_id, product_name,
product_type, sale_price,
(select avg(sale_price) from product) as sale_price_all
from product
NO4:
这个考察的是关联子查询,我的方法是,先写子查询的逻辑,然后搞清楚它返回的是什么,返回的就是一个标量,之后需要嵌入主查询做FOR循环!!
select product_id, product_name, product_type, sale_price , (SELECT AVG(sale_price)
FROM product as table2
where table2.product_type = table1.product_type
group by product_type) as avg_sale_price
from product as table1
运行结果如下:
函数介绍
这里只挑了一些我不太常用的,一般忘记了就现用现查。
1、算术函数
ROUND( 对象数值,保留小数的位数 ) ----四舍五入
2、字符串函数
SUBSTRING(对象字符串 FROM 截取的起始位置 FOR 截取的字符数)---- 字符串的截取,sql中下标从1开始
例子:从product_name第3个字符开始,往后取2个
select product_name,substring(product_name from 3 for 2) as sub_string
from product;
substring_index(原始字符串, 分隔符,n) :以分隔符split,取第n个分割之前的内容,起始索引为1,倒序起始索引为-1
类似于python中的split()函数
SELECT SUBSTRING_INDEX('www.mysql.com', '.', 2);
结果是www.mysql
获取第N个元素,需要嵌套N次,取-1
例如:获取 'www.mysql.com' 中的 mysql
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX('www.mysql.com', '.', 2), '.' , -1);
3、日期函数
---获取当前时间
select current_timestamp;
---获取当前日期
select current_date;
---获取当前时刻
select current_time;
截取日期元素 extract (这个很实用)
SELECT CURRENT_TIMESTAMP as now,
EXTRACT(YEAR FROM CURRENT_TIMESTAMP) AS year,
EXTRACT(MONTH FROM CURRENT_TIMESTAMP) AS month,
EXTRACT(DAY FROM CURRENT_TIMESTAMP) AS day,
EXTRACT(HOUR FROM CURRENT_TIMESTAMP) AS hour,
EXTRACT(MINUTE FROM CURRENT_TIMESTAMP) AS MINute,
EXTRACT(SECOND FROM CURRENT_TIMESTAMP) AS second;
4、转换函数
COALESCE – 将NULL转换为其他值
CAST(转换前的值 AS 想要转换的数据类型)
谓词
谓词:返回值为真值的函数
1、LIKE
---用‘%’正则,前方一致、中间一致和后方一致
--前方:dddaa匹配
SELECT *
FROM samplelike
WHERE strcol LIKE 'ddd%';
--中间:abcdddcsv匹配
SELECT *
FROM samplelike
WHERE strcol LIKE '%ddd%';
--后方:aaasvddd匹配
SELECT *
FROM samplelike
WHERE strcol LIKE '%ddd';
---用‘_’正则任意1个字符
aadddcsv匹配
SELECT *
FROM samplelike
WHERE strcol LIKE '__ddd___';
2、between :闭区间,[],
where column between 100 and 1000
3、IN
where column IN (123,345,578,12346)
4、善于用“子查询”代替 IN 和 NOT IN
使用子查询即可保持 sql 语句不变,极大提高了程序的可维护性,这是系统开发中需要重点考虑的内容。实际生活中,某个门店的在售商品是不断变化的,使用 in 谓词就需要经常更新 sql 语句,降低了效率,提高了维护成本;实际上,某个门店的在售商品可能有成百上千个,手工维护在售商品编号真是个大工程。
-- NOT IN 使用子查询作为参数,取出未在大阪门店销售的商品的销售单价
SELECT product_name, sale_price
FROM product
WHERE product_id NOT IN (SELECT product_id
FROM shopproduct
WHERE shop_id = '000A');
5、exist & not exist: 是否存在符合条件的记录,这个应该是个非常好用的谓词!!!因为你可以把【限定条件】全都放到【关联子查询】中,同时不必要想子查询需要筛选出来什么,直接子查询select * 或者select 1就好!!!!!
SELECT product_name, sale_price
FROM product AS p
WHERE EXISTS (SELECT 1 -- 这里可以书写适当的常数
FROM shopproduct AS sp
WHERE sp.shop_id = '000C'
AND sp.product_id = p.product_id);
SELECT product_name, sale_price
FROM product AS p
WHERE NOT EXISTS (SELECT *
FROM shopproduct AS sp
WHERE sp.shop_id = '000A'
AND sp.product_id = p.product_id);
6.CASE
注意END不可省略!!!
SELECT product_name,
CASE WHEN product_type = '衣服' THEN CONCAT('A : ',product_type)
WHEN product_type = '办公用品' THEN CONCAT('B : ',product_type)
WHEN product_type = '厨房用具' THEN CONCAT('C : ',product_type)
ELSE NULL
END AS abc_product_type
FROM product;
7、聚合函数+CASE WHEN ... THEN... ELSE...END 在业务中是经常用到的!!
核心思想是:先想你最终需要的表的列是哪几个,然后再插入计算的东西。(要什么拿什么)
第一步构建框架:
select name,
......chinese,
......math,
......english
from
table1
group by name;
第二步,填充内容:
select name,
sum(case when subject = '语文' then score else 0 end) as chinese,
sum(case when subject = '数学' then score else 0 end) math,
sum(case when subject = '英语' then score else 0 end) english
from
table1
group by name;
搞定~~~
哦~终于到了第二部分的练习了!!LET'S DO IT!!
NO.1:
对
NO.2:
结果:
带上了null以后,所有的结果都没有了,这是因为,谓词是对真值的判断,Null没有对应的真值,它是unknown
NO.3:
SELECT
sum(case when sale_price <= 1000 then 1 else 0 end) as low_price,
sum(case when sale_price > 1001 and sale_price < 3001 then 1 else 0 end) as low_price,
sum(case when sale_price > 3001 then 1 else 0 end) as high_price
from product
NICE~
好嘞,今天的打卡就到这里了~
完成和坚持是第一步,所以今天又走了一步呢~我想你也和我一样