【SQL03】复杂一点的查询

感谢datawhale开展的每月组队学习,本章教材ref:SQL Task03

视图

在这里插入图片描述

常见操作

** 创建视图**

CREATE VIEW <视图名称>(<列名1>,<列名2>,...) AS <SELECT语句>

-- 例子
CREATE VIEW productsum (product_type, cnt_product)
AS
SELECT product_type, COUNT(*)
  FROM product
 GROUP BY product_type ;

我们可以直接从数据表创建视图,也可以从视图创建视图(但,不要这样,性能会很慢)
视图名必须是unique的,不可以和别的视图/表重名

** 修改视图 **

ALTER VIEW <视图名称> AS <SELECT语句>

-- 例子
ALTER VIEW productSum
    AS
        SELECT product_type, sale_price
          FROM Product
         WHERE regist_date > '2009-09-11';

在这里插入图片描述

  • 视图的列名会随着SELECT改变诶,不用自己去写

** 更新视图 **
在这里插入图片描述
原本的product表的这个地方也会随之改变。这有点像shallow copy浅拷贝的意思?视图像是一个reference。

虽然这样可以修改成功,但是不建议使用这种方式。
我们在创建视图时也尽量不要通过视图修改表
是的,shallow copy、deep copy虽然好理解,但是有的时候在实际应用中是很容易没注意就把原数据改了。还是不要用更新视图内容比较好
在这里插入图片描述

删除视图
在这里插入图片描述

子查询

在这里插入图片描述

  • 查询出销售单价高于平均销售单价的商品

    -- 销售单价高于平均销售单价的商品
    SELECT 
    	*
    FROM 
    	product
    WHERE 
    	sale_price > (SELECT AVG(sale_price) FROM product);
    
  • 查询出注册日期最晚的那个商品

    -- 查询出注册日期最晚的那个商品
    SELECT *
    FROM product
    WHERE regist_date = (SELECT MAX(regist_date) FROM product);
    
  • 你能猜到这段代码的运行结果是什么吗?运行一下看看与你想象的结果是否一致

    SELECT product_id,
       product_name,
       sale_price,
       (SELECT AVG(sale_price)
          FROM product) AS avg_price
    FROM product;
    

    从product表中获取三个列信息:product_id, product_name, sale_price, 算出表中所有产品的平均售价放在最后一列

  • 你能理解这个例子在做什么操作么

    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
       	a.product_type, product_name, sale_price
    FROM
    	product AS a
    	LEFT JOIN (
      	SELECT b.product_type, AVG(sale_price) as average_price
    	FROM product AS b
    	GROUP BY b.product_type
    ) as c
    ON
    a.product_type = c.product_type
    WHERE
    	sale_price > average_price;
    

    教材给出的query结构截图可能有点问题…因为在UPDATE VIEW更新视图的时候,原表就已经被改动掉了,办公用品类的有两个:一个打孔器500元,圆珠笔被改成了5000元了已经。但是这里给出的output截图,比自己产品类平均值还高的商品还是打孔器(500元)。
    emmm… 也有可能是写教材的大佬做了什么不commit/rollback操作…

各种各样的函数

算数函数

在这里插入图片描述

字符串函数

在这里插入图片描述

日期函数

在这里插入图片描述

转换函数

在这里插入图片描述

谓语

在这里插入图片描述

CASE 表达式

在这里插入图片描述

练习题

  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
    
    -- 3.1
    CREATE VIEW ViewPractice5_1 (product_name, sale_price, regist_date)
    AS
    SELECT
        product_name, sale_price, regist_date
    FROM
        product
    WHERE
        regist_date = '2009-09-20'
        AND
        sale_price >= 1000;
    

    小tips:
    可以在创建视图之前先执行一下后面的SELECT语句,看一下是否正确。
    我一开始粗心大于等于没写等于,执行结果少一行,再drop view,再重新创建… 也算是做个删除视图的练习吧 😅
    在这里插入图片描述

  2. 向习题一中创建的视图 ViewPractice5_1 中插入如下数据,会得到什么样的结果呢?

    INSERT INTO ViewPractice5_1 VALUES (' 刀子 ', 300, '2009-11-02');
    

    我的猜想:大概是会在原表中也增加一行?那没有value的那些其他列的值会为NULL?❌
    我的猜想是错误的,因为:这个视图是原表的一个窗口,而原表product中 我们设置product_id, product_type应当是 NOT NULL的,如果我们通过这个视图以这样的方式insert数据,我们无法给要求不能为空的product_idproduct_type赋值。因此MySQL不允许我们这样做。
    从给出的报错信息来看,如果我们给product_idproduct_type提前设置一个默认值,比如product_id自动increment或许是可以实现的。
    在这里插入图片描述
    如果要创建一个updatable的视图的话,创建的那个SELECT子句里不能包含:

    • 聚合函数
    • DISTINCT
    • GROUP BY 子句
    • HAVING 子句
    • UNION、UNION ALL 子句
    • LEFT JOIN、OUTER JOIN
    • SELECT 或是 WHERE 子句 中有 subquery 子查询
    • 从另一个不可updatable的视图创建
    • reference only to literal values?
    • multiple references to any column of the base table

    可以使用

    	SELECT
        	table_name,
        	is_updatable
    	FROM
        	information_schema.VIEWS
    	WHERE
     		TABLE_SCHEMA = 'classicmodels';
    

    来查看视图是不是updatable

  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
    
    CREATE VIEW AvgPriceByType
    AS
    SELECT
           product_id,
           product_name,
           a.product_type,
           a.sale_price,
           b.avg_sale_price
    FROM
         product a,
         (
         SELECT
            product_type, AVG(sale_price) as avg_sale_price
        FROM
             product
        GROUP BY
            product_type
             ) b
    WHERE
        a.product_type = b.product_type;
    

    思路:
    在这里插入图片描述

  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
    
    SELECT
           product_id,
           product_name,
           a.product_type,
           a.sale_price,
           b.avg_sale_price
    FROM
         product a,
         (SELECT
            product_type, AVG(sale_price) as avg_sale_price
    	  FROM
    	    product
    	  GROUP BY
            product_type) b
    WHERE
        a.product_type = b.product_type;
    

    思路
    在这里插入图片描述

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

    感觉… emmm是的吧,最起码大部分是的
    可以慢慢总结一下
    函数中含有NULL 结果全都变为NULL的有:
    - CONCAT(str1, str2, NULL) --> NULL

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

    SELECT product_name, purchase_price
      FROM product
     WHERE purchase_price NOT IN (500, 2800, 5000);
    

    从表product中获取产品名称和购买价格, 取出的产品应满足:购买价格不是 500元,不是2800元,不是5000元(统统只要一块钱,不是
    在这里插入图片描述

    SELECT product_name, purchase_price
      FROM product
     WHERE purchase_price NOT IN (500, 2800, 5000, NULL);
    


    因为 WHERE purchase_price NOT IN (500, 2800, 5000, NULL) 转换成OR来写的话就是

    	WHERE purchase_price <> 500
    	OR purchase_price <> 2800
    	OR purchase_price <> 5000
    	OR purchase_price <> NULL
    

    那我们上期学过了,取NULL或取非NULL如果用 =<> 结果都会是空

  7. 按照销售单价( sale_price)对练习 3.6 中的 product(商品)表中的商品进行如下分类。

    • 低档商品:销售单价在1000日元以下(T恤衫、办公用品、叉子、擦菜板、 圆珠笔)
    • 中档商品:销售单价在1001日元以上3000日元以下(菜刀)
    • 高档商品:销售单价在3001日元以上(运动T恤、高压锅)

    请编写出统计上述商品种类中所包含的商品数量的 SELECT 语句,结果如下所示。

    执行结果

    	low_price | mid_price | high_price
    	----------+-----------+------------
            5 |         1 |         2
    
    	-- solution 1
    SELECT COUNT(CASE WHEN sale_price<=1000 THEN product_id ELSE NULL END) as low_price,
           COUNT(CASE WHEN 1000<sale_price AND sale_price<=3000 THEN product_id ELSE NULL END) as mid_price,
           COUNT(CASE WHEN sale_price>3000 THEN product_id ELSE NULL END) as high_price
    FROM product;
    
    -- solution 2
    SELECT SUM(CASE WHEN sale_price<=1000 THEN 1 ELSE 0 END) as low_price,
           SUM(CASE WHEN 1000<sale_price AND sale_price<=3000 THEN 1 ELSE 0 END) as mid_price,
           SUM(CASE WHEN sale_price>3000 THEN 1 ELSE 0 END) as high_price
    FROM product;
    

    方法一:
    我们通过CASE表达式获得满足条件的所有product_id, 然后使用COUNT()函数去统计总共有多少个product_id,使用AS 赋予别名
    在这里插入图片描述
    ⚠️ ELSE NULL,对于COUNT()函数,如果有NULL

    • COUNT(*) 包含NULL的数据行数
    • COUNT(<列名>) 不包含NULL的数据函数

    方法二
    第二个方法是用到了SUM()函数。一样,先通过CASE表达式获得满足条件的项?并赋予其值为1,不满足的为0。这个时候其实跟第一个方法意思一样的,但是第一个方法可能如果表里有重复商品的话就更好一点,第二个方法就没办法去除重复的部分。最后利用加法SUM()就可以计算出满足条件的商品数量
    在这里插入图片描述

    • 满足条件为1
    • 不满足条件为0
    • 求和
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值