美文网首页
《SQL基础教程》学习笔记Ch5

《SQL基础教程》学习笔记Ch5

作者: los_pollos | 来源:发表于2018-03-28 11:56 被阅读0次

5复杂查询

5-1视图

视图和表

当我们创建表时,会通过INSERT语句将数据保存到数据库中,而数据库中的数据会被保存到计算机的存储设备中;但是使用视图不会将数据保存在数据库中,实际上视图只保存SELECT语句,从视图中读取数据时,视图会在内部执行该SELECT语句并创建出一张临时表。

视图的优点:
1.无需保存数据,节省存储设备的容量
2.可以将频繁使用的SELECT语句保存为视图

创建视图的方法
--创建ProductSum视图
CREATE VIEW ProductSum (product_type, cnt_product) --视图的列名
AS
SELECT product_type, COUNT(*)
  FROM Product
 GROUP BY product_type;
--使用视图
SELECT product_type, cnt_product
  FROM ProductSum;
5-1.png

在FROM子句中使用视图的查询通常有两个步骤:
1.首先执行定义视图的SELECT子句;
2.根据得到的结果,再执行在FROM子句中使用视图的SELECT子句

定义视图时,可以使用WHERE,GROUP BY,HAVING等语句
此外应该避免下列的多重视图(以视图的基础创建视图):

CREATE VIEW ProductSumJim (product_type, cnt_product)
AS
SELECT product_type, cnt_product
  FROM ProductSum
 WHERE product_type = '办公用品';
视图的限制

1.定义视图时不能使用ORDER BY子句
这是因为视图和表一样,数据行是没有顺序的
2.只在某些条件下可以进行更新
更新语句:INSERT,DELETE,UPDATE

比较有代表性的条件:
SELECT子句未使用DISTINCT;
FROM子句中只有一张表;
未使用GROUP BY子句;
未使用HAVING子句。

视图和表需要同时进行更新,因而通过汇总(GROUP BY)得到的视图无法进行更新。

--能够进行更新的视图
CREATE VIEW ProductJim (product_id, product_name, product_type, sale_price, purchase_price, regist_date)
AS
SELECT *
  FROM Product
 WHERE product_type = '办公用品';
--向视图中添加数据行
INSERT INTO ProductJim VALUES ('0009', '印章', '办公用品', 95, 10, '2009-11-30');

另外,需要注意的是,在PostgreSQL运行上面的插入语句会报错,由于PostgreSQL初始设定视图为只读,我们通过下列语句来允许PostgreSQL对视图进行更新:

CREATE OR REPLACE RULE insert_rule
AS ON INSERT 
TO  ProductJim DO INSTEAD
INSERT INTO Product VALUES(
    new.product_id,
    new.product_name,
    new.product_type,
    new.sale_price,
    new.purchase_price,
    new.regist_date);

执行的结果:视图及原表中数据均已被插入

删除视图
DROP VIEW ProductSum;

在PostgreSQL中此句会出错,由于关联视图存在的原因,修改为:

DROP VIEW ProductSum CASCADE;

5-2子查询

首先来复习一下前面是怎么使用视图来查询的:

--创建ProductSum视图
CREATE VIEW ProductSum (product_type, cnt_product) --视图的列名
AS
SELECT product_type, COUNT(*)
  FROM Product
 GROUP BY product_type;
--使用视图
SELECT product_type, cnt_product
  FROM ProductSum;

所谓子查询:

-- 在FROM子句中直接书写定义视图的SELECT语句
SELECT product_type, cnt_product
  FROM (SELECT product_type, COUNT(*) AS cnt_product
         FROM Product
         GROUP BY product_type) AS ProductSum;

这两种方式得到的结果完全一致。
执行顺序是先执行括号内的SELECT语句,再执行括号外的SELECT语句。

--尝试增加子查询的层数
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;
5-2.png
子查询的名称

原则上,子查询必须使用AS设定名称

标量子查询

标量子查询指的是必须且只能返回1行1列的子查询
假设我们想要“查询出销售单价高于平均销售单价的商品”

--错误的语句
--在WHERE子句中不能使用聚合函数
SELECT product_id, product_name, sale_price
  FROM Product
 WHERE sale_price > AVG(sale_price); --错误

要解决这个问题,我们可以使用标量子查询语句

--计算平均销售单价的标量子查询
SELECT AVG(sale_price)
  FROM Product;
--选取出销售单价高于全部商品的平均单价的商品
SELECT product_id, product_name, sale_price
  FROM Product
 WHERE sale_price > (SELECT AVG(sale_price)
                       FROM Product);
5-3.png
标量子查询的书写位置

能够使用常数或者列名的地方,无论是SELECT子句、GROUP BY子句、HAVING子句还是ORDER BY子句,几乎所有的地方都可以使用

--在SELECT子句中使用标量子查询
SELECT product_id,
       product_name,
       sale_price,
        (SELECT AVG(sale_price)
               FROM Product)  AS avg_price
FROM Product;
--在HAVING子句中使用标量子查询
SELECT product_type, AVG(sale_price)
  FROM Product
 GROUP BY product_type
HAVING AVG(sale_price) > (SELECT AVG(sale_price)
                            FROM Product);
使用标量子查询时的注意事项

标量子查询只能够返回单一值,如果返回多行值,它就不再是标量子查询,而仅仅是一个普通的子查询

--由于不是标量子查询,因此不能在SELECT子句中使用
SELECT product_id, 
       product_name,
       sale_price,
       (SELECT AVG(sale_price)
         FROM Product
         GROUP BY product_type) AS avg_price
  FROM Product;

该段会报错,这是由于子查询的结果是三个而不是一个,不再是标量子查询,不可以写在SELECT子句中

5-3关联子查询

普通的子查询和关联子查询的区别

假设这次我们想要“查询出某个商品类中高于此类商品平均销售单价的商品”

--按照商品种类计算平均价格
SELECT AVG(sale_price)
  FROM Product
 GROUP BY product_type;
--发生错误的子查询
SELECT product_id, product_name, sale_price
  FROM Product
 WHERE sale_price > (SELECT AVG(sale_price)
                       FROM Product
                    GROUP BY product_type);

这种方法显然是错误的,因为普通的子查询被当做了标量子查询。
为了解决这个问题,可以利用关联子查询:

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);
5-4.png

在这里起到关键作用的是在子查询中添加的WHERE子句的条件,它的意思是在同一商品种类中,对商品的销售单价和平均单价进行比较。
由于作为比较对象的都是同一张Product表,因此要使用P1和P2两个别名。
需要注意的是:
1.关联子查询也是用来对集合进行切分的
2.结合条件一定要写在子查询中

相关文章

网友评论

      本文标题:《SQL基础教程》学习笔记Ch5

      本文链接:https://www.haomeiwen.com/subject/wgpecftx.html