datawhale9月组队学习task03复杂查询

Posted 临风而眠

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了datawhale9月组队学习task03复杂查询相关的知识,希望对你有一定的参考价值。

datawhale9月组队学习task03复杂查询

preparation

一.视图

图片来源:https://www.bilibili.com/video/BV1va4y1x7tW?from=search&seid=15245999763303735560&spm_id_from=333.337.0.0

1.何为视图

  • 视图是可视化的表
  • 是虚拟的表
  • 视图依据SELECT语句来创建
    • 操作视图时会根据创建视图的SELECT语句生成一张虚拟表,再在这张虚拟表上做SQL操作

2.视图 VS 表

  • 视图没有保存实际的数据 表中保存的是实际数据

    视图中保存的是SELECT语句

  • 视图不是表,视图是虚表,视图依赖于表

​ 用户可以直接操作基本表,在磁盘中存储是在数据文件中的

​ 但作为用户并不需要太关心底层的存储,除了操作表之外还可以操作视图

​ 视图从基本表中取数据,但不真正存放数据

3.Why need 视图

  • 可保存频繁使用的SELECT语句,提高效率
  • 可使用户看到的数据更清晰
  • 可不对外公开数据表全部字段,增加数据保密性
  • 只存放视图的定义,不会出现数据冗余

4.How to create 视图

  • 基本语法

    CREATE VIEW <视图名称>(<列名1>,<列名2>,...) AS <SELECT语句>
    
    • 其中SELECT 语句需要书写在 AS 关键字之后。 SELECT 语句中列的排列顺序和视图中列的排列顺序相同, SELECT 语句中的第 1 列就是视图中的第 1 列, SELECT 语句中的第 2 列就是视图中的第 2 列,以此类推。而且视图的列名是在视图名称之后的列表中定义的
    • 注意的是视图名在数据库中需要是唯一的,不能与其他视图和表重名
    CREATE VIEW view_name AS
    SELECT column_name(s)
    FROM table_name
    WHERE condition;
    
  • 视图不仅可以基于真实表,我们也可以在视图的基础上继续创建视图

    • 但还是应该尽量避免这种操作。这是因为对多数 DBMS 来说, 多重视图会降低 SQL 的性能

注意

在一般的DBMS中定义视图时不能使用ORDER BY语句

  • 下面这个是错的:

  • 因为视图和表一样,数据行都没有顺序

  • mysql中视图的定义是允许使用 ORDER BY 语句的,但是若从特定视图进行选择,而该视图使用了自己的 ORDER BY 语句,则视图定义中的 ORDER BY 将被忽略

基于单表的视图
CREATE VIEW productsum (product_type, cnt_product)
AS
SELECT product_type, COUNT(*)
  FROM product
 GROUP BY product_type ;

这时输入SHOW TABLES;命令,就会发现多了productsum

不过像navicat、datagrip这种还是把视图和表分开的

  • 查看视图还是可用SELECT语句

  • 或者直接用可视化工具

基于多表的视图
  • 先创建一张表shop_product

    CREATE TABLE shop_product
    (shop_id    CHAR(4)       NOT NULL,
     shop_name  VARCHAR(200)  NOT NULL,
     product_id CHAR(4)       NOT NULL,
     quantity   INTEGER       NOT NULL,
     PRIMARY KEY (shop_id, product_id));
    
    INSERT INTO shop_product (shop_id, shop_name, product_id, quantity) VALUES ('000A',	'东京',		'0001',	30);
    INSERT INTO shop_product (shop_id, shop_name, product_id, quantity) VALUES ('000A',	'东京',		'0002',	50);
    INSERT INTO shop_product (shop_id, shop_name, product_id, quantity) VALUES ('000A',	'东京',		'0003',	15);
    INSERT INTO shop_product (shop_id, shop_name, product_id, quantity) VALUES ('000B',	'名古屋',	'0002',	30);
    INSERT INTO shop_product (shop_id, shop_name, product_id, quantity) VALUES ('000B',	'名古屋',	'0003',	120);
    INSERT INTO shop_product (shop_id, shop_name, product_id, quantity) VALUES ('000B',	'名古屋',	'0004',	20);
    INSERT INTO shop_product (shop_id, shop_name, product_id, quantity) VALUES ('000B',	'名古屋',	'0006',	10);
    INSERT INTO shop_product (shop_id, shop_name, product_id, quantity) VALUES ('000B',	'名古屋',	'0007',	40);
    INSERT INTO shop_product (shop_id, shop_name, product_id, quantity) VALUES ('000C',	'大阪',		'0003',	20);
    INSERT INTO shop_product (shop_id, shop_name, product_id, quantity) VALUES ('000C',	'大阪',		'0004',	50);
    INSERT INTO shop_product (shop_id, shop_name, product_id, quantity) VALUES ('000C',	'大阪',		'0006',	90);
    INSERT INTO shop_product (shop_id, shop_name, product_id, quantity) VALUES ('000C',	'大阪',		'0007',	70);
    INSERT INTO shop_product (shop_id, shop_name, product_id, quantity) VALUES ('000D',	'福冈',		'0001',	100);
    
  • product表和shop_product表的基础上创建视图

    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
    

5.How to alter 视图结构

  • 基本语法

    ALTER VIEW <视图名> AS <SELECT语句>
    
    • 视图名在数据库中须唯一
      • 不可与其他视图和表重名
  • 修改前面的那个productSum视图

    ALTER VIEW productSum
        AS
            SELECT product_type, sale_price
              FROM Product
             WHERE regist_date > '2009-09-11';
    
    • 修改后的视图:

6.How to update 视图内容

  • 因为视图是一个虚拟表,所以对视图的操作就是对底层基础表的操作,所以在修改时只有满足底层基本表的定义才能成功修改

  • 更新视图

    上面的productSum视图不包括以上限制条件

    UPDATE productsum
       SET sale_price = '5000'
     WHERE product_type = '办公用品';
    

  • 查看原表

    原表那个也变成5000了!

    但是当时的修改语句是WHERE product_type = '办公用品'; 为什么打孔器那个没有变为5000呢?

7.How to delete 视图

  • 基本语法

    DROP VIEW <视图名1> [ , <视图名2>]
    
    • 需要相应权限才能成功删除
  • 删除productsum

    DROP VIEW productsum;
    
    • 删掉了之后继续操作这个视图就会报错

二.子查询

引入

1.What is 子查询

  • 将用来定义视图的SELECT语句嵌套在另一个查询语句内部的查询
    • 在SELECT子句中先计算子查询,子查询结果作为外层另一个查询的过滤条件,查询可以基于一个表或者多个表

2.子查询与视图的关系

接着上面的引入

  • 子查询就是将用来定义视图的 SELECT 语句直接用于 FROM 子句当中。其中AS studentSum可以看作是子查询的名称,而且由于子查询是一次性的,所以子查询不会像视图那样保存在存储介质中, 而是在 SELECT 语句执行之后就消失了

3.嵌套子查询(尽量避免)

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语句不仅会难以理解而且执行效率也会很差,所以要尽量避免这样的使用。

4.标量子查询

  • 标量:单一

    • 标量子查询:单一子查询
    • 所谓的单一是要求我们的SQL语句只能返回一个值
      • 即返回表中具体的某一行的某一列

标量子查询有啥用

  • 直接看个例子:通过标量子查询语句查询出销售单价高于平均单价的商品

    SELECT product_id, product_name, sale_price
      FROM product
     WHERE sale_price > (SELECT AVG(sale_price) FROM product);
    

  • 还可以这样用

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

5.关联子查询

  • 查询与子查询间存在联系

    • 如何建立联系

  • 查询与子查询的联系

三.各种函数

1.算术函数

先构造一个samplemath表格

-- DDL :创建表
USE shop;
DROP TABLE IF EXISTS samplemath;
CREATE TABLE samplemath
(m NUMERIC(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; -- 提交事务
-- 查询表内容
  • 加减乘除

  • ABS 绝对值

  • MOD 求余数

    • MOD 是计算除法余数(求余)的函数,是 modulo 的缩写。小数没有余数的概念,只能对整数列求余数。

      注意:主流的 DBMS 都支持 MOD 函数,只有SQL Server 不支持该函数,其使用%符号来计算余数

  • ROUND 四舍五入

    • 语法:ROUND( 对象数值,保留小数的位数 )
SELECT m,
ABS(m) AS abscol,
n ,p,
MOD(n,p) AS mod_col,
MOD(n,p) AS mod_col,
ROUND(m,1) AS round_col
FROM samplemath;

2.字符串函数

  • 先构造samplestr用于学习
-- DDL :创建表
USE  shop;
DROP TABLE IF EXISTS samplestr;
CREATE TABLE samplestr
(str1 VARCHAR (40),
str2 VARCHAR (40),
str3 VARCHAR (40)
);
-- DML:插入数据
START TRANSACTION;
INSERT INTO samplestr (str1, str2, str3) VALUES ('opx',	'rt', NULL);
INSERT INTO samplestr (str1, str2, str3) VALUES ('abc', 'def', NULL);
INSERT INTO samplestr (str1, str2, str3) VALUES ('太阳',	'月亮', '火星');
INSERT INTO samplestr (str1, str2, str3) VALUES ('aaa',	NULL, NULL);
INSERT INTO samplestr (str1, str2, str3) VALUES (NULL, 'xyz', NULL);
INSERT INTO samplestr (str1, str2, str3) VALUES ('@!#$%', NULL, NULL);
INSERT INTO samplestr (str1, str2, str3) VALUES ('ABC', NULL, NULL);
INSERT INTO samplestr (str1, str2, str3) VALUES ('aBC', NULL, NULL);
INSERT INTO samplestr (str1, str2, str3) VALUES ('abc哈哈',  'abc', 'ABC');
INSERT INTO samplestr (str1, str2, str3) VALUES ('abcdefabc', 'abc', 'ABC');
INSERT INTO samplestr (str1, str2, str3) VALUES ('micmic', 'i', 'I');
COMMIT;
-- 确认表中的内容

  • CONCAT 拼接

    • CONCAT(str1,str2,str3)
  • LENGTH 字符串长度

    • LENGTH(字符串)
  • LOWER 小写转换

    • LOWER 函数只能针对英文字母使用,它会将参数中的字符串全都转换为小写。该函数不适用于英文字母以外的场合,不影响原本就是小写的字符。
  • ERPLACE 字符串替换

    • REPLACE( 对象字符串,替换前的字符串,替换后的字符串 )
  • SUBSTRING 字符串的截取

    • SUBSTRING (对象字符串 FROM 截取的起始位置 FOR 截取的字符数)
  • 想试试在datagrip里面搞

    • 先选择Query Console

    • 然后选择相应的数据库

    • 试试!点击绿色按钮执行脚本

      SELECT
          str1,
          str2,
          str3,
          CONCAT(str1,str2,str3) AS str_concat,
          LENGTH(str1) AS len_str,
          LOWER(str1) AS low_str,
          REPLACE(str1,str2,str3) AS rep_str,
          SUBSTRING(str1 FROM 3 FOR 2) AS sub_str
      FROM
          samplestr;
      
    • 跳出result

3.日期函数

  • 下面是一些被标准 SQL 承认的可以应用于绝大多数 DBMS 的函数

    • CURRENT_DATE 当前日期

    • CURRENT_TIME 当前时间

    • CURRENT_TIEMSTAMP 当前日期和时间

    • 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.转换函数

  • CAST 类型转换

    • CAST(转换前的值 AS 想要转换的数据类型)
      
      • -- 将字符串类型转换为数值类型
        SELECT CAST('0001' AS SIGNED INTEGER) AS int_col;
        
  • COALESCE 将NULL转换为其他值

    • COALESCE(数据1,数据2,数据3……)
      
      • COALESCE 是 SQL 特有的函数。该函数会返回可变参数 A 中左侧开始第 1个不是NULL的值。参数个数是可变的,因此可以根据需要无限增加。

        在 SQL 语句中将 NULL 转换为其他值时就会用到转换函数。

    • SELECT COALESCE(NULL, 11) AS col_1,
      COALESCE(NULL, 'hello world', NULL) AS col_2,
      COALESCE(NULL, NULL, '2020-11-01') AS col_3;
      

四.谓词

1.What is 谓词

  • 返回值为真值的函数
    • 包括TRUE/FALSE/UNKONWN
  • 主要谓词
    • LIKE
    • BETWEEN
    • ISN NULL 、 IS NOT NULL
    • IN
    • EXISTS

2.LIKE谓词 – 用于字符串的部分一致查询

  • 部分一致大体可以分为

    • 前方一致
    • 中间一致
    • 后方一致
  • 查看之前就导入的表samplelike

  • 前方一致:选出“dddabc”

    • 前方一致即作为查询条件的字符串(这里是“ddd”)与查询对象字符串起始部分相同

    • SELECT *
      FROM samplelike
      WHERE strcol LIKE 'ddd%';
      
    • 其中的%是代表“零个或多个任意字符串”的特殊符号,本例中代表“以ddd开头的所有字符串”

  • 中间一致:选取出“abcddd”“dddabc”“abdddc”

    • 中间一致即查询对象字符串中含有作为查询条件的字符串,无论该字符串出现在对象字符串的最后还是中间都没有关系

    • SELECT *
      FROM samplelike
      WHERE strcol LIKE '%ddd%';
      
  • 后方一致:选取出“abcddd“

    • 后方一致即作为查询条件的字符串(这里是“ddd”)与查询对象字符串的末尾部分相同

      SELECT *
      FROM samplelike
      WHERE strcol LIKE '%ddd';
      

  • _下划线匹配任意 1 个字符

    • SELECT *
      FROM samplelike
      WHERE strcol LIKE 'ab___';
      

总结

综合如上三种类型的查询可以看出,查询条件最宽松,也就是能够取得最多记录的是中间一致。这是因为它同时包含前方一致和后方一致的查询结果。

3.BETWEEN谓词 – 用于范围查询

  • 如选取销售单价100~1000元的商品

    SELECT product_name, sale_price
    FROM product
    WHERE sale_price BETWEEN 100 AND 1000;
    

  • 注意上面是闭区间

    • 若要改为开区间:

    • SELECT product_name, sale_price
      FROM product
      WHERE sale_price >100
      AND sale_price <1000;
      

4.IS NULL、 IS NOT NULL – 用于判断是否为NULL

SELECT product_name, sale_price
FROM product
WHERE purchase_price IS NULL;

以上是关于datawhale9月组队学习task03复杂查询的主要内容,如果未能解决你的问题,请参考以下文章

datawhale9月组队学习task01环境搭建,初始数据库

datawhale9月组队学习task04集合运算

datawhale9月组队学习task05SQL高级操作

datawhale9月组队学习task06 SQL秋招题

Datawhale 吃瓜教程组队学习 task01

Datawhale7月组队学习task3数据重构