目录
一、视图
1. 什么是视图
2. 视图和表的区别
3. 为什么存在视图
4. 如何创建视图
4.1 基于单表的视图
4.2 基于多表的视图
5. 修改视图结构
6. 更新视图内容
7. 删除视图
二、子查询
1. 什么是子查询
2. 子查询与视图的关系
3. 嵌套子查询
4. 标量子查询
5. 关联子查询
练习1
三、函数
1. 算术函数
2. 字符串函数
3. 日期函数
4. 转换函数
四、谓语
五、CASE表达式
1. 不同分支得到不同列值
2. 实现列方向上的聚合
3. 实现行转列
练习2
总结
从SQL角度操作视图和操作表看起完全相同
视图是虚拟的表,视图是依据SELECT语句来创建的,操作视图时会根据创建视图的SELECT语句生成一张虚拟表,然后在虚拟表上做SQL操作
视图不保存实际的数据,作为一个窗口,通过窗口看到数据表中实际的数据,视图是基于真实表的一张虚拟表,其数据来源均建立在真实表的基础上。
CREATE VIEW <视图名称>(<列名1>,<列名2>,……) AS
CREATE VIEW productsum (product_type, cnt_product)
AS
SELECT product_type, COUNT(*)
FROM product
GROUP BY product_type;
CREATE VIEW view_shop_product(product_type, sale_price, shop_name)
AS
SELECT product_type, sale_price, shop_name
FROM product,
shop_product
WHERE product.product_id = shop_product.product_id;
在视图的基础上查询
语句与在表上的操作一致
SELECT *
FROM view_shop_product
WHERE product_type = '衣服';
ALTER VIEW <视图名> AS
修改视图的结构,可以新增查询条件,也可以新增字段,新增字段时一定要保证视图字段和查询字段一致。
ALTER VIEW view_shop_product(product_type, sale_price, shop_name)
AS
SELECT product_type, sale_price, shop_name
FROM product,
shop_product
WHERE product.product_id = shop_product.product_id
AND regist_date>'2009-09-11';
对视图的操作基于底层表的操作,修改时只有满足底层基本表的定义才能修改成功。包含以下任意一种,都不能被更新:
UPDATE productsum
SET sale_price = '5000'
WHERE prodcut_type = '办公用品';
通过视图的修改只能透过窗口能看到内容
注意:不推荐透过视图去改表内容
DROP VIEW <视图名1>[ , <视图名2>];
需要有相应的权限
DROP VIEW productsum;
一个查询语句嵌套另一个查询语句内部的查询。先计算子查询,子查询结果作为外层另一个查询的过滤条件,查询可以基于一个表或多个表。
子查询可以将用来定义视图的SELECT语句直接用于FROM子句中。子查询是一次性的,不会被保存在存储介质中,视图是会被保存在存储介质中
SELECT *
FROM
(SELECT product_name, shop_name
FROM product,
shop_product
WHERE product.product_id = shop_product.product_id
) AS shop;
多个SELECT嵌套查询,不建议使用过多的嵌套查询,会影响SQL的性能。
单一的子查询。需要返回表中具体的某一行的某一列
1. 查询出product表中sale_price大于平均销售单价的产品
SELECT *
FROM product
WHERE sale_price > (SELECT AVG(sale_price) FROM product);
也可以将平均销售单价显示出来
SELECT * ,
(SELECT AVG(sale_price) FROM product) AS avg_price
FROM product
WHERE sale_price > (SELECT AVG(sale_price) FROM product);
2. 查询register_date最晚的商品
SELECT *
FROM product
WHERE regist_date = (SELECT max(regist_date) FROM product);
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);
根据结果我们会发现,查询到的是大于每一个product_type的平均值,相当于分组之后求平均值;之前查询到的是大于总的平均销售,没有按照每一个product_type去求平均数
关联子查询:
1. 依据product表创建视图view_practice,满足一下三条件
CREATE VIEW view_practice (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';
SELECT * FROM view_practice;
思路:首先需要通过product查找到相应的字段并限制相应的条件,之后按照视图创建的语句将SQL语句整理好
2. 向view_practice插入一条数据
INSERT INTO view_practice VALUES ('菜刀',300,'2009-11-02');
CREATE VIEW view_practice_t (product_name, sale_price, regist_date)
AS
SELECT product_name, sale_price, regist_date
FROM product ;
INSERT INTO view_practice_t VALUES ('菜刀',300,'2009-11-02');
思路:在插入的过程中,结果显示无法插入,考虑到我做了限制条件,我将单价改为1000,日期改2009-09-20,发现依旧无法插入数据,然后我建立了一张全新的不做限制的表单,再执行插入依旧无法插入。(我在百度上显示如果按照条件mysql的视图是可以插入的,但是我测试的结果是不可以,这是我疑惑的点)
3. 编写SELECT语句,sale_price_all列是全部商品的平均销售单价
SELECT product_id, product_name, product_type, sale_price,
(SELECT AVG(sale_price) FROM product) AS sale_price_all
FROM product;
4. 编写SQL语句,包含按product_type分类的平均销售额
SELECT product_type, product_name, sale_price,
(SELECT AVG(sale_price) FROM product AS p2 WHERE p1.product_type = p2.product_type
GROUP BY product_type) avg_sale_price
FROM product AS p1;
思路:再原来的product的基础上增加一列,首先我们需要查询相互按product_type分类的平均单价,之后再将两张表通过product_type关联起来(也可以使用join 将两张表拼接起来达到一样的效果)
数据类型的转换和值的转换
谓语就是返回值为真值的函数,包括TRUE/FALSE/UNKNOWN
CASE WHEN <求值表达式> THEN <表达式>
WHEN <求值表达式> THEN <表达式>
……
ELSE <表达式>
END
SELECT product_name,
product_type,
CASE WHEN product_type = '衣服' THEN CONCAT('A', '-', product_name)
WHEN product_type = '厨房用具' THEN CONCAT('B-', product_name)
ELSE NULL
END new_product_type
FROM product;
SELECT SUM(CASE WHEN product_type = '衣服' THEN sale_price ELSE 0 END) sum_price_cloth
FROM product;
CREATE TABLE score
( name VARCHAR(255) NOT NULL,
subject VARCHAR(255) NOT NULL,
score INT
);
INSERT INTO score VALUES('张三','语文',93),
('张三','数学',88),
('张三','英语',91),
('李四','语文',87),
('李四','数学',90),
('李四','英语',77);
SELECT name,
SUM(CASE WHEN subject='语文' THEN score ELSE 0 END) chinese,
SUM(CASE WHEN subject='数学' THEN score ELSE 0 END) math,
SUM(CASE WHEN subject='英语' THEN score ELSE 0 END) english
FROM score
GROUP BY name;
总结:
1. 运算或函数中含有NULL时,结果全都变为NULL?(是的)
运算中含有NULL值,结果会变为NULL值,运算前可以使用IFNULL(字段,0)将值转换为0参与运算。使用聚合函数时,含有NULL值的记录也不会参与聚合
2. 对product表执行语句,观察结果
SELECT product_name, purchase_price
FROM product
WHERE purchase_price NOT IN (500,2800,5000);
SELECT product_name, purchase_price
FROM product
WHERE purchase_price NOT IN (500,2800,5000,NULL);
含有NOT IN 条件中含有NULL值,结果也变为了NULL
3. 按照以下条件进行分类
计算这三种分类的所含商品数量
SELECT
SUM(CASE WHEN sale_price<=1000 THEN 1 ELSE 0 END ) low_price,
SUM(CASE WHEN sale_price BETWEEN 1001 AND 3000 THEN 1 ELSE 0 END) mid_price,
SUM(CASE WHEN sale_price >= 3001 THEN 1 ELSE 0 END ) high_price
FROM product;
因为我们使用的product表的产品是唯一的,因此可以使用 1 和 0 来进行计数,最后求和得到商品数量,但是不是普遍适用的方法,个人觉得下面的思路是普遍的方法:先找到满足条件的产品,之后对产品进行去重统计
SELECT
COUNT(DISTINCT(CASE WHEN sale_price<=1000 THEN product_id ELSE NULL END)) low_price,
COUNT(DISTINCT(CASE WHEN sale_price BETWEEN 1001 AND 3000 THEN product_id ELSE NULL END)) mid_price,
COUNT(DISTINCT(CASE WHEN sale_price>=3001 THEN product_id ELSE NULL END)) high_price
FROM product;
1. 着重注意运算和函数对于NULL的使用,如果存在NULL值在计算前转换为0
2. 注意COALESCE函数的使用
3. CASE WHEN行转列的使用