SQL复杂查询知识梳理

视图

视图是虚拟的表。与包含数据的表不一样,视图只包含使用时动态检索数据的查询。

为什么使用视图

  • 重用SQL语句
  • 简化复杂的SQL操作,编写查询后,可以方便地重用它而不必知道它的基本查询细节
  • 使用表的组成部分而不是整张表
  • 保护数据,可以给用户授予表的特定部分的访问权限而不是整张表的访问权限
  • 更改数据格式和表示,视图可返回与底层表的表示和格式不同的数据

性能问题:
因为视图不包含数据,所以每次使用视图时,都必须处理查询执行时所需的任一个检索。如果用多个联结和过滤创建了复杂的视图或者嵌套了视图,可能会发现性能下降的很厉害,所以,在部署使用大量视图的应用前,先进行测试。

视图的规则和限制

  • 与表一样,视图必须唯一命名(不能给视图取与其他视图和表相同的名字)
  • 对于可以创建的视图数目没有限制
  • 为了创建视图,必须具有足够的访问权限
  • 视图可以嵌套,可以利用从其他视图中检索数据的查询来构造一个视图
  • ORDER BY 可以用在视图中,但如果从该视图中检索数据的SELECT语句中也包含ORDER BY,那么该视图的ORDER BY将被覆盖
  • 视图不能索引,也不能有关联的触发器或默认值
  • 视图可以和表一起使用

使用视图

  • 创建视图
CREATE VIEW 视图名
  • 使用SHOW CREATE VIEW viewname;查看创建视图的语句。
  • 使用DROP删除视图
DROP VIEW viewname;
  • 更新视图时,先使用DROP在使用CREATE,也可以直接用CREATE OR REPLACE VIEW。如果要更新的视图不存在,第二条更新语句会创建一个视图,如果要更新视图存在,则第二条更新语句会替换掉原有视图。

更新视图

通常视图是可以更新的(即可以对它们使用INSERT,UPDATE和DELETE)更新一个视图将更新表(视图本身没有数据)如果对视图进行增加删除行,其实是对表进行增加删除行。

但并非所有的视图都可以更新,如果MySQL不能正确的确定更新的基数据,则不能进行更新,实际上,大多数视图都是不可更新的,因为视图主要用于数据检索。如果视图中以下操作,就不可以进行视图的更新:

  • 分组(使用GROUP BY和HAVING)
  • 联结
  • 子查询
  • 聚集函数(Min(),Count(),Sum()等)
  • DISTINCT
  • 导出(计算)列

使用视图简化复杂联结

视图极大的简化了复杂SQL语句的使用,使用视图,可以一次性编写基础的SQL,然后按需多次使用。

CREATE VIEW productcustomers AS
SELECT cust_name,cust_contact,prod_id
FROM customers,orders,orderitems
WHERE customers.cust_id = orders.cust_id
AND orderitems.order_num = orders.order_num

创建了一个名为productcustomers的视图,联结了三个表,返回已订购了任意产品的所有客户的列表。
检索订购了产品TNT2的客户:

SELECT cust_name,cust_contact
FROM  productcustomers
WHERE prod_id ='TNT2';
cust_namecust_contact
Coyote IncY Lee
Yosemite PlaceY sam

查看视图

查看视图和查看表的语句相同

desc 视图名;
select * from 视图名

用视图过滤不想要数据

CREATE VIEW list AS 
SELECT id,username,price,date
FROM dataw
WHERE date IS NOT NULL;

将date为null的数据过滤掉,不在视图中显示。
在这里插入图片描述

使用视图与计算字段

CREATE VIEW data AS
SELECT
id,
username
date,
price*i AS iprice 
FROM dataw;

在这里插入图片描述

子查询

任何sql语句都是查询,但是一般指的是SELECT语句。
sql允许创建子查询,即嵌套在其他查询中的查询。
子查询中最常见的使用是在WHERE子句的IN操作符中,以及用来填充计算列。

使用子查询进行过滤

SELECT product_type, cnt_product
FROM (SELECT *
        FROM (SELECT product_type, 
                      COUNT(*) AS cnt_product
                FROM product 
               GROUP BY product_type) AS productsum
       WHERE cnt_product = 4) AS productsum2;
其中最内层的子查询我们将其命名为productSum,这条语句根据product_type分组并查询个数,第二层查询中将个数为4的商品查询出来,最外层查询product_type和cnt_product两列。 虽然嵌套子查询可以查询出结果,但是随着子查询嵌套的层数的叠加,SQL语句不仅会难以理解而且执行效率也会很差,所以要尽量避免这样的使用。

关联子查询

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);
  • 关联查询处理过程:
    首先执行不带WHERE的主查询
    根据主查询讯结果匹配product_type,获取子查询结果
    将子查询结果再与主查询结合执行完整的SQL语句

练习题一

  • 3.1
    创建出满足下述三个条件的视图(视图名称为 ViewPractice5_1)。使用 product(商品)表作为参照表,假设表中包含初始状态的 8 行数据。
    条件 1:销售单价大于等于 1000 日元。
    条件 2:登记日期是 2009 年 9 月 20 日。
    条件 3:包含商品名称、销售单价和登记日期三列。
    对该视图执行 SELECT 语句的结果如下所示。
SELECT * FROM ViewPractice5_1;

执行结果

product_name | sale_price | regist_date
--------------±-----------±-----------
T恤衫 |   1000 | 2009-09-20
菜刀 | 3000 | 2009-09-20

CREATE VIEW ViewPractice5_1 AS 
SELECT product_name, sale_price, regist_date
FROM product WHERE sale_price >= 1000 ADN regist_date = "2009-09-20";
  • 3.2
    向习题一中创建的视图 ViewPractice5_1 中插入如下数据,会得到什么样的结果呢?
INSERT INTO ViewPractice5_1 VALUES (' 刀子 ', 300, '2009-11-02');

对原始数据表不产生影响,只有对原始数据表进行操作,视图数据和原始数据表才会更新。

  • 3.3
    请根据如下结果编写 SELECT 语句,其中 sale_price_all 列为全部商品的平均销售单价。

product_id | product_name | product_type | sale_price | sale_price_all
------------±------------±-------------±-----------±--------------------
0001 | T恤衫 | 衣服 | 1000 | 2097.5000000000000000
0002 | 打孔器 | 办公用品 | 500 | 2097.5000000000000000
0003 | 运动T恤 | 衣服 | 4000 | 2097.5000000000000000
0004 | 菜刀 | 厨房用具 | 3000 | 2097.5000000000000000
0005 | 高压锅 | 厨房用具 | 6800 | 2097.5000000000000000
0006 | 叉子 | 厨房用具 | 500 | 2097.5000000000000000
0007 | 擦菜板 | 厨房用具 | 880 | 2097.5000000000000000
0008 | 圆珠笔 | 办公用品 | 100 | 2097.5000000000000000

SELECT product_id, product_name, product_type, sale_price, 
(SELECT avg(sale_price) FROM product) AS sale_price_all
FROM product;

  • 3.4
    请根据习题一中的条件编写一条 SQL 语句,创建一幅包含如下数据的视图(名称为AvgPriceByType)。

product_id | product_name | product_type | sale_price | avg_sale_price
------------±------------±-------------±-----------±--------------------
0001 | T恤衫 | 衣服 | 1000 |2500.0000000000000000
0002 | 打孔器 | 办公用品 | 500 | 300.0000000000000000
0003 | 运动T恤 | 衣服 | 4000 |2500.0000000000000000
0004 | 菜刀 | 厨房用具 | 3000 |2795.0000000000000000
0005 | 高压锅 | 厨房用具 | 6800 |2795.0000000000000000
0006 | 叉子 | 厨房用具 | 500 |2795.0000000000000000
0007 | 擦菜板 | 厨房用具 | 880 |2795.0000000000000000
0008 | 圆珠笔 | 办公用品 | 100 | 300.0000000000000000

提示:其中的关键是 avg_sale_price 列。与习题三不同,这里需要计算出的 是各商品种类的平均销售单价。这与使用关联子查询所得到的结果相同。 也就是说,该列可以使用关联子查询进行创建。问题就是应该在什么地方使用这个关联子查询。

CREATE VIEW AvgPriceByType AS 
SELECT p1.product_id, p1.product_name, p1.product_type, p1.sale_price, p2.avg_sale_price
FROM product AS p1, 
	(SELECT product_type,  avg(sale_price) AS avg_sale_price FROM product
    GROUP BY product_type) AS p2
WHERE p1.product_type = p2.product_type;

SQL函数

算数函数

创建samplemath表并插入数据。

-- DDL :创建表
USE shop;
DROP TABLE IF EXISTS samplemath;
CREATE TABLE samplemath
(m float(10,3),
n INT,
p INT);
-- DML :插入数据
START TRANSACTION; -- 开始事务
INSERT INTO samplemath(m, n, p) VALUES (500, 0, NULL);
INSERT INTO samplemath(m, n, p) VALUES (-180, 0, NULL);
INSERT INTO samplemath(m, n, p) VALUES (NULL, NULL, NULL);
INSERT INTO samplemath(m, n, p) VALUES (NULL, 7, 3);
INSERT INTO samplemath(m, n, p) VALUES (NULL, 5, 2);
INSERT INTO samplemath(m, n, p) VALUES (NULL, 4, NULL);
INSERT INTO samplemath(m, n, p) VALUES (8, NULL, 3);
INSERT INTO samplemath(m, n, p) VALUES (2.27, 1, NULL);
INSERT INTO samplemath(m, n, p) VALUES (5.555,2, NULL);
INSERT INTO samplemath(m, n, p) VALUES (NULL, 1, NULL);
INSERT INTO samplemath(m, n, p) VALUES (8.76, NULL, NULL);
COMMIT; -- 提交事务
-- 查询表内容
SELECT * FROM samplemath;
  • ABS – 绝对值
    语法:ABS( 数值 )
  • MOD – 求余数
    语法:MOD( 被除数,除数 )
  • ROUND – 四舍五入
    语法:ROUND( 对象数值,保留小数的位数 )
    ROUND 函数用来进行四舍五入操作。
SELECT m,
ABS(m)ASabs_col ,
n, p,
MOD(n, p) AS mod_col,
ROUND(m,1)ASround_colS
FROM samplemath;

在这里插入图片描述

注意:当参数 保留小数的位数 为变量时,可能会遇到错误,请谨慎使用变量。

字符串函数

  • CONCAT – 拼接
    语法:CONCAT(str1, str2, str3)
  • LENGTH – 字符串长度
    语法:LENGTH( 字符串 )
  • LOWER – 小写转换
  • UPPER 函数用于大写转换。
    LOWER 函数只能针对英文字母使用,它会将参数中的字符串全都转换为小写。
  • REPLACE – 字符串的替换
    语法:REPLACE( 对象字符串,替换前的字符串,替换后的字符串 )
  • SUBSTRING – 字符串的截取
    语法:SUBSTRING (对象字符串 FROM 截取的起始位置 FOR 截取的字符数)
    使用 SUBSTRING 函数 可以截取出字符串中的一部分字符串。截取的起始位置从字符串最左侧开始计算,索引值起始为1。

日期函数

  • CURRENT_DATE – 获取当前日期
    在这里插入图片描述
  • CURRENT_TIME – 当前时间
SELECT CURRENT_TIME

在这里插入图片描述

  • CURRENT_TIMESTAMP – 当前日期和时间
SELECT CURRENT_TIMESTAMP

在这里插入图片描述

  • EXTRACT – 截取日期元素
    语法:EXTRACT(日期元素 FROM 日期)
    【例子】
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;

在这里插入图片描述

谓词

在这里插入图片描述
谓词:返回值为真值(TRUE/FALSE/UNKNOWN)的函数。

LIKE - 字符串的部分一致查询

SELECT *FROM  dataw WHERE username LIKE 'data%';

在这里插入图片描述
 %:0 字符以上的任意字符串。
_:任意 1 个字符。

SELECT *FROM dataw WHERE username LIKE 'datawh___';

在这里插入图片描述

SELECT *FROM dataw WHERE username LIKE 'datawh_____';

在这里插入图片描述

BETWEEN - 范围查询

SELECT * FROM dataw  WHERE price BETWEEN 4 AND 9;

re在这里插入图片描述
BETWEEN会包含临界值,不需要临界值可以用>和<来处理

SELECT * FROM dataw  WHERE price > 4 AND price< 9;

在这里插入图片描述

IS NULL、IS NOT NULL - 判断是否为 NULL

为了选取部分值为 NULL 的列的数据,不能使用 =,只能使用 IS NULL

SELECT * FROM dataw WHERE date IS NULL;

在这里插入图片描述
取反(不为空的数据),请使用 IS NOT NULL。

SELECT * FROM dataw WHERE date IS NOT NULL;

在这里插入图片描述

IN - OR 的简便用法

在这里插入图片描述
用IN替换上面的SQL语句:
在这里插入图片描述
否定形式 NOT IN:
在这里插入图片描述

  • IN 和 NOT IN 是无法选取 NULL 数据的

EXIST

作用:判断是否存在满足某种条件的记录
 很多时候基本上可以使用 IN 或 NOT IN 来代替该谓词。
在这里插入图片描述
在这里插入图片描述
 NOT EXIST 与 EXIST 相反,不存在:在这里插入图片描述

使用子查询作为 IN 谓词的参数

IN 和 NOT IN 谓词具有其它谓词没有的用法,它的参数可以是子查询。

SELECT price,username 
FROM dataw 
WHERE id IN(SELECT id FROM dataw WHERE username="datawhale");

在这里插入图片描述

SELECT price,username 
FROM dataw 
WHERE id NOT IN(SELECT id FROM dataw WHERE username="datawhale");

在这里插入图片描述

CASE 表达式

CASE 表达式:(条件)分歧。
语法:

CASE WHEN <判断表达式> THEN <表达式>
     WHEN <判断表达式> THEN <表达式>
     ...
     ELSE <表达式>
END

判断表达式类似“键 = 值”的形式,返回值为真值(TRUE/FALSE/UNKNOW)的表达式。如果结果为真,就会返回 THEN 子句中的表达式;如果不为真,就跳转到下一条 WHEN 子句的判断中;如果到最后的 WHEN 子句都不为真,就执行最后一条 ELSE 的表达式。
在这里插入图片描述
简化代码:
在这里插入图片描述

行转列

在这里插入图片描述
在这里插入图片描述

练习题二

  • 3.5
    运算或者函数中含有 NULL 时,结果全都会变为NULL ?(判断题)

会。

  • 3.6
    对本章中使用的 product(商品)表执行如下 2 条 SELECT 语句,能够得到什么样的结果呢?

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);
  • 3.7
    按照销售单价( sale_price)对练习 6.1 中的 product(商品)表中的商品进行如下分类。
    低档商品:销售单价在1000日元以下(T恤衫、办公用品、叉子、擦菜板、 圆珠笔)
    中档商品:销售单价在1001日元以上3000日元以下(菜刀)
    高档商品:销售单价在3001日元以上(运动T恤、高压锅)
    请编写出统计上述商品种类中所包含的商品数量的 SELECT 语句,结果如下所示。
    执行结果
low_price | mid_price | high_price
----------+-----------+------------
        5 |         1 |         2
SELECT 
sum(CASE WHEN sale_price <= 1000 THEN 1 ELSE 0 END) AS low_price,
sum(CASE WHEN  sale_price BETWEEN 1001 AND 3000 THEN  1 ELSE 0 END ) AS mid_price,
sum(CASE WHEN sale_price  >3000 THEN 1 ELSE 0 END) AShigh_price
FROM product;

文章部分内容引用
SQL基础知识梳理:https://www.cnblogs.com/liqingwen/p/6572284.html

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值