MySQL|复杂一点的查询: 视图,子查询,函数,谓词,CASE表达式

学习链接:http://datawhale.club/t/topic/475

3.1 视图

3.1.1 什么是视图

什么是视图:视图是一个虚拟的表,不同于直接操作数据表,视图是依据SELECT语句来创建的(会在下面具体介绍),所以操作视图时会根据创建视图的SELECT语句生成一张虚拟表,然后在这张虚拟表上做SQL操作。

3.1.2 视图与表有什么区别

《sql基础教程**第2版》用一句话非常凝练的概括了视图与表的区别—“是否保存了实际的数据”。所以视图并不是数据库真实存储的数据表,它可以看作是一个窗口,通过这个窗口我们可以看到数据库表中真实存在的数据。所以我们要区别视图和数据表的本质,即视图是基于真实表的一张虚拟的表,其数据来源均建立在真实表的基础上。

视图和表的区别

“视图不是表,视图是虚表,视图依赖于表”

3.1.3 为什么会存在视图

那既然已经有数据表了,为什么还需要视图呢?主要有以下几点原因:

  • 1 通过定义视图可以将频繁使用的SELECT语句保存以提高效率。
  • 2 通过定义视图可以使用户看到的数据更加清晰。
  • 3 通过定义视图可以不对外公开数据表全部字段,增强数据的保密性。
  • 4 通过定义视图可以降低数据的冗余。

3.1.4 如何创建视图

视图的创建
mysql> create view productsum (product_type,cnt_product)
    -> as
    -> select product_type,count(*)
    -> from product
    -> group by product_type;
视图的创建

基于多表的视图:我们在product表和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);
image.png
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;
image.png

3.1.5 如何修改视图结构

mysql> alter view productsum
    -> as
    -> select product_type,sale_price
    -> from product
    -> where regist_data > '2009-09-11';
修改视图

3.1.6 如何更新视图内容

mysql> update productsum
    -> set sale_price = '5000'
    -> where product_type = '办公用品';
修改了部分数据

原数据表格

刚才修改视图的时候是设置product_type='办公用品’的商品的sale_price=5000,为什么原表的数据只有一条做了修改呢?
还是因为视图的定义,视图只是原表的一个窗口,所以它修改也只能修改透过窗口能看到的内容。
注意:这里虽然修改成功了,但是并不推荐这种使用方式。而且我们在创建视图时也尽量使用限制不允许通过视图来修改表。

3.1.7 如何删除视图

mysql> drop view productsum;
已删除productsum视图

3.2 子查询

3.2.1什么是子查询

子查询指一个查询语句嵌套在另一个查询语句内部的查询,这个特性从 MySQL 4.1 开始引入,在 SELECT 子句中先计算子查询,子查询结果作为外层另一个查询的过滤条件,查询可以基于一个表或者多个表。

SELECT stu_name
FROM (
         SELECT stu_name, COUNT(*) AS stu_cnt
           FROM students_info
          GROUP BY stu_age) AS studentSum;

3.2.1 子查询和视图的关系

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

3.2.3 嵌套子查询

ELECT 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;
image.png

3.2.4 标量子查询

标量就是单一的意思,那么标量子查询也就是单一的子查询,那什么叫做单一的子查询呢?
所谓单一就是要求我们执行的SQL语句只能返回一个值,也就是要返回表中具体的某一行的某一列。例如我们有下面这样一张表


image.png

3.2.5 标量子查询的作用

SELECT product_id, product_name, sale_price
  FROM product
 WHERE sale_price > (SELECT AVG(sale_price) FROM product);
image.png
mysql> select product_id,product_name,sale_price,
    -> (select avg(sale_price) from product) as avg_price
    -> from product;
image.png

上面的这条语句首先后半部分查询出product表中的平均售价,前面的sql语句在根据WHERE条件挑选出合适的商品。
由于标量子查询的特性,导致标量子查询不仅仅局限于 WHERE 子句中,通常任何可以使用单一值的位置都可以使用。也就是说, 能够使用常数或者列名的地方,无论是 SELECT 子句、GROUP BY 子句、HAVING 子句,还是 ORDER BY 子句,几乎所有的地方都可以使用。

3.2.6 关联子查询

关联子查询既然包含关联两个字那么一定意味着查询与子查询之间存在着联系。这种联系是如何建立起来的呢?

  • 目的:选取出各商品种类中高于该商品种类的平均销售单价的商品
image.png

关联查询的执行过程

  • 1首先执行不带WHERE的主查询
  • 2根据主查询结果匹配product_type,获取子查询结果
  • 3将子查询结果再与主查询结合执行完整的SQL语句
    在子查询中像标量子查询,嵌套子查询或者关联子查询可以看作是子查询的一种操作方式即可。

小结

视图和子查询是数据库操作中较为基础的内容,对于一些复杂的查询需要使用子查询加一些条件语句组合才能得到正确的结果。但是无论如何对于一个SQL语句来说都不应该设计的层数非常深且特别复杂,不仅可读性差而且执行效率也难以保证,所以尽量有简洁的语句来完成需要的功能。

3.1 练习题

创建出满足下述三个条件的视图(视图名称为 ViewPractice5_1)。使用 product(商品)表作为参照表,假设表中包含初始状态的 8 行数据。

条件 1:销售单价大于等于 1000 日元。
条件 2:登记日期是 2009 年 9 月 20 日。
条件 3:包含商品名称、销售单价和登记日期三列。
对该视图执行 SELECT 语句的结果如下所示。


image.png
mysql> create view ViewPractice5_1(product_name,sale_price,regist_data)
    -> as
    -> select product_name,sale_price,regist_data
    -> from product
    -> where (sale_price >= 1000) and (regist_data='2009-09-20');
image.png

3.2

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

INSERT INTO ViewPractice5_1 VALUES (' 刀子 ', 300, '2009-11-02');
  • ERROR 1423 (HY000): Field of view 'datawhale.viewpractice5_1' underlying table doesn't have a default value

3.3

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


image.png
mysql> select product_id,product_name,product_type,sale_price,
    -> (select avg(sale_price) from product) as sale_price_all
    -> from product;
image.png

3.4

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


image.png
-- 创建视图的语句
CREATE VIEW AvgPriceByType AS
SELECT product_id,
       product_name,
       product_type,
       sale_price,
       (SELECT AVG(sale_price)
          FROM product p2
         WHERE p1.product_type = p2.product_type
         GROUP BY p1.product_type) AS avg_sale_price
 FROM product p1;

-- 确认视图内容
SELECT * FROM AvgPriceByType;
image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,366评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,521评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,689评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,925评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,942评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,727评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,447评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,349评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,820评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,990评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,127评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,812评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,471评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,017评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,142评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,388评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,066评论 2 355

推荐阅读更多精彩内容