当前位置:网站首页>[PSQL] 复杂查询
[PSQL] 复杂查询
2022-07-31 06:02:00 【wy_hhxx】
SQL基础教程读书笔记 MICK,第5章 复杂查询
示例程序下载 http://www.ituring.com.cn/book/1880
说明:如下笔记中的测试基于postgresql14
命令行连接本地PSQL: psql -U <username> -d <dbname> -h 127.0.0.1 -W
目录
5 复杂查询
5-1 视图
视图和表
从 SQL 的角度来看视图就是一张表。
数据库中的数据实际上会被保存到计算机的存储设备(通常是硬盘)中。我们通过 SELECT 语句查询数据时,实际上就是从存储 设备(硬盘)中读取数据,进行各种计算之后,再将结果返回给用户这样 一个过程。 但是使用视图时并不会将数据保存到存储设备之中,而且也不会将数据保存到其它任何地方。实际上视图保存的是 SELECT 语句。 我们从视图中读取数据时,视图会在内部执行该 SELECT 语句并创建出 一张临时表。
视图的优点
(1)视图无需保存数据,因此可以节省存储设备的容量。
(2)可以将频繁使用的 SELECT 语句保存成视图,不用每次都重新书写。
而且,视图中的数据会随着原表的变化自动更新。视图归根到底就是SELECT 语句,所谓“参照视图”也就是“执行 SELECT 语句”的意思。
创建视图的方法
语法5-1 创建视图的CREATE VIEW语句
CREATE VIEW 视图名称(<视图列名1>, <视图列名2>, ……)
AS
<SELECT语句>
SELECT 语句需要书写在 AS 关键字之后。SELECT 语句中的第 1 列就是视图中的第 1 列,SELECT 语句中的第 2 列就是视图中的第 2 列,以此类推。
代码清单5-2 ProductSum视图
CREATE VIEW ProductSum (product_type, cnt_product)
AS
SELECT product_type, COUNT(*)
FROM Product
GROUP BY product_type;
代码清单5-3 使用视图
shop=# SELECT product_type, cnt_product FROM ProductSum;
product_type | cnt_product
--------------+-------------
衣服 | 2
办公用品 | 2
厨房用具 | 4
(3 rows)
shop=#
在 FROM 子句中使用视图的查询,通常有如下两个步骤:
① 首先执行定义视图的 SELECT 语句
② 根据得到的结果,再执行在 FROM 子句中使用视图的 SELECT 语句
视图的限制① ——定义视图时不能使用ORDER BY子句
视图和表一样,数据行都是没有顺序的。
说明:有些 DBMS 在定义视图的语句中是可以使用 ORDER BY 子句的 A,但是这并不是通用的语法。
视图的限制② ——对视图进行更新
如果定义视图的 SELECT 语句能够
满足某些条件,那么这个视图就可以被更新。下面就给大家列举一些比较
具有代表性的条件。
① SELECT 子句中未使用 DISTINCT
② FROM 子句中只有一张表
③ 未使用 GROUP BY 子句
④ 未使用 HAVING 子句
使用视图来保存原表的汇总结果时,是无法判断如何将视图的更改反映到原表中的。例如,
INSERT INTO ProductSum VALUES ('电器制品', 5);
向视图 ProductSum 中添加数据 (' 电器制品 ', 5) 时,原表 Product 应该如何更新才好呢?按理说应该向表中添加商品种类为“电器制品”的 5 行数据,但是这些商品对应的商品编号、商品名称和销售单价等我们都不清楚。
能够更新视图的情况
不是通过汇总得到的视图就可以进行更新。
代码清单5-5 可以更新的视图
CREATE VIEW ProductJim (product_id, product_name, product_type,
sale_price, purchase_price, regist_date)
AS
SELECT *
FROM Product
WHERE product_type = '办公用品';
代码清单5-6 向视图中添加数据行
INSERT INTO ProductJim VALUES ('0009', '印章', '办公用品', 95, 10, '2009-11-30');
执行结果:
shop=# SELECT * FROM ProductJim;
product_id | product_name | product_type | sale_price | purchase_price | regist_date
------------+--------------+--------------+------------+----------------+-------------
0002 | 打孔器 | 办公用品 | 500 | 320 | 2009-09-11
0008 | 圆珠笔 | 办公用品 | 100 | | 2009-11-11
0009 | 印章 | 办公用品 | 95 | 10 | 2009-11-30
(3 rows)
shop=# SELECT * FROM Product;
product_id | product_name | product_type | sale_price | purchase_price | regist_date
------------+--------------+--------------+------------+----------------+-------------
0001 | T恤 | 衣服 | 1000 | 500 | 2009-09-20
0002 | 打孔器 | 办公用品 | 500 | 320 | 2009-09-11
0003 | 运动T恤 | 衣服 | 4000 | 2800 |
0004 | 菜刀 | 厨房用具 | 3000 | 2800 | 2009-09-20
0005 | 高压锅 | 厨房用具 | 6800 | 5000 | 2009-01-15
0006 | 叉子 | 厨房用具 | 500 | | 2009-09-20
0007 | 擦菜板 | 厨房用具 | 880 | 790 | 2008-04-28
0008 | 圆珠笔 | 办公用品 | 100 | | 2009-11-11
0009 | 印章 | 办公用品 | 95 | 10 | 2009-11-30
(9 rows)
shop=#
删除视图
语法5-2 删除视图的DROP VIEW语句
DROP VIEW 视图名称(<视图列名1>, <视图列名2>, ……)
代码清单5-7 删除视图
DROP VIEW ProductSum;
在PostgreSQL中,如果删除以视图为基础创建出来的多重视图,由于存在关联的视图,因此会发生如下错误。
shop=# CREATE VIEW ProductJim1 (product_id, product_name, product_type,
shop(# sale_price, purchase_price, regist_date)
shop-# AS
shop-# SELECT *
shop-# FROM ProductJim;
CREATE VIEW
shop=#
shop=# DROP VIEW ProductJim;
ERROR: cannot drop view productjim because other objects depend on it
DETAIL: view productjim1 depends on view productjim
HINT: Use DROP ... CASCADE to drop the dependent objects too.
根据提示使用CASCADE选项来删除关联视图
shop=# DROP VIEW ProductJim CASCADE;
NOTICE: drop cascades to view productjim1
DROP VIEW
shop=#
5-2 子查询
重点:
1) 一言以蔽之,子查询就是一次性视图(SELECT语句)。与视图不同,子查询在SELECT语句执行完毕之后就会消失。
2) 由于子查询需要命名,因此需要根据处理内容来指定恰当的名称。
3) 标量子查询就是只能返回一行一列的子查询。
子查询和视图
子查询就是将用来定义视图的SELECT语句直接用于FROM子句当中。
代码清单5-8 视图ProductSum和确认用的SELECT语句
-- 根据商品种类统计商品数量的视图
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-9 所示。
代码清单5-9 子查询
-- 在FROM子句中直接书写定义视图的SELECT语句
SELECT product_type, cnt_product
FROM ( SELECT product_type, COUNT(*) AS cnt_product
FROM Product
GROUP BY product_type ) AS ProductSum;
子查询就是将用来定义视图的 SELECT 语句直接用于 FROM 子句当中。
虽然“AS ProductSum”就是子查询的名称,该名称在 SELECT 语句执行之后就消失了。 实际上,该 SELECT 语句包含嵌套的结构,首先会执行 FROM 子句 中的 SELECT 语句,然后才会执行外层的 SELECT 语句。
子查询的名称
上述例子中我们给子查询设定了 ProductSum 名称。原则上子查询必须设定名称。
标量子查询
而标量子查询则有一个特殊的限制,那就是必须而且只能返回 1 行 1 列的结果,也就是返回表中某一行的某一列的值。
由于返回的是单一的值,因此标量子查询的 返回值可以用在 = 或者 <> 这样需要单一值的比较运算符之中。这也正是 标量子查询的优势所在。
在WHERE子句中使用标量子查询
查询出销售单价高于平均销售单价的商品,像下面这样使用AVG 函数会发生错误。
在WHERE子句中不能使用聚合函数
shop=# SELECT product_id, product_name, sale_price
shop-# FROM Product
shop-# WHERE sale_price > AVG(sale_price);
ERROR: aggregate functions are not allowed in WHERE
LINE 3: WHERE sale_price > AVG(sale_price);
^
shop=#
代码清单5-11 计算平均销售单价的标量子查询
shop=# SELECT AVG(sale_price) FROM Product;
avg
-----------------------
2097.5000000000000000
(1 row)
shop=#
代码清单5-12 选取出销售单价(sale_price)高于全部商品的平均单价的商品
shop=# SELECT product_id, product_name, sale_price FROM Product
shop-# WHERE sale_price > (SELECT AVG(sale_price) FROM Product);
product_id | product_name | sale_price
------------+--------------+------------
0003 | 运动T恤 | 4000
0004 | 菜刀 | 3000
0005 | 高压锅 | 6800
(3 rows)
shop=#
标量子查询的书写位置
能够使用常数或者列名的地方,无论是 SELECT 子句、GROUP BY 子句、HAVING 子句,还是 ORDER BY 子句,几乎所有的地方都可以使用。
代码清单5-14 在HAVING子句中使用标量子查询
shop=# SELECT product_type, AVG(sale_price) FROM Product GROUP BY product_type
shop-# HAVING AVG(sale_price) > (SELECT AVG(sale_price) FROM Product);
product_type | avg
--------------+-----------------------
衣服 | 2500.0000000000000000
厨房用具 | 2795.0000000000000000
(2 rows)
shop=#
5-3 关联子查询
普通的子查询和关联子查询的区别
如下可以选取出办公用品、衣服和厨房用具三类商品中高于该类商品的平均销售单价的商品。
代码清单5-16 通过关联子查询按照商品种类对平均销售单价进行比较
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 P1.product_type = P2.product_type是关键,该条件的意思就是,在同一商品种类中对各商品的销售单价和平均单价进行比较。关联子查询实际只能返回 1 行结果。
执行结果:
product_type | product_name | sale_price
--------------+--------------+------------
办公用品 | 打孔器 | 500
衣服 | 运动T恤 | 4000
厨房用具 | 菜刀 | 3000
厨房用具 | 高压锅 | 6800
(4 rows)
shop=#
结合条件一定要写在子查询中
-- 错误的关联子查询书写方法
SELECT product_type, product_name, sale_price
FROM Product AS P1
WHERE P1.product_type = P2.product_type
AND sale_price > (SELECT AVG(sale_price)
FROM Product AS P2
GROUP BY product_type);
================================================
执行结果
ERROR: missing FROM-clause entry for table "p2"
LINE 3: WHERE P1.product_type = P2.product_type
^
shop=#
该书写方法违反了关联名称的作用域规则。
如前所述,SQL 是按照先内层子查询后外层查询的顺序来执行的。子查询执行结束时只会留下执行结果,P2 表已经不存在了 。因此, 在执行外层查询时,返回“不存在使用该名称的表”的错误。
附:
法则 5-1 表中存储的是实际数据,而视图中保存的是从表中取出数据所使用的SELECT语句。
法则 5-2 应该将经常使用的SELECT语句做成视图。
法则 5-3 应该避免在视图的基础上创建视图。
法则 5-4 定义视图时不要使用ORDER BY子句。
法则 5-5 视图和表需要同时进行更新,因此通过汇总得到的视图无法进行更新。
法则 5-6 子查询作为内层查询会首先执行。
法则 5-7 标量子查询就是返回单一值的子查询。
法则 5-8 在细分的组内进行比较时,需要使用关联子查询。
边栏推荐
- 项目 - 如何根据最近30天、最近14天、最近7天、最近24小时、自定义时间范围查询MySQL中的数据?
- 【Go语言入门】一文搞懂Go语言的最新依赖管理:go mod的使用
- Obtaining server and client information
- 毫米波技术基础
- Database Principles Homework 3 — JMU
- 【网络攻防】常见的网络攻防技术——黑客攻防(通俗易懂版)
- 二叉树的还原(反序列化)
- js原型详解
- Run the NPM will pop up to ask "how are you going to open this file?"
- 2. (1) Chained storage of stack, operation of chain stack (illustration, comment, code)
猜你喜欢
Project exercise - memorandum (add, delete, modify, check)
Zotero | Zotero translator plugin update | Solve the problem that Baidu academic literature cannot be obtained
Conditional statements of shell (test, if, case)
【Go报错】go go.mod file not found in current directory or any parent directory 错误解决
【Go语言刷题篇】Go完结篇函数、结构体、接口、错误入门学习
批量翻译软件免费【2022最新版】
Redux state management
数据库概论 - MySQL的简单介绍
芯塔电子斩获第十一届中国双创大赛芜湖赛区桂冠
【微服务】 微服务学习笔记二:Eureka注册中心的介绍及搭建
随机推荐
如何在uni-app中选择一个合适的UI组件库
小实战项目之——吃货联盟订餐系统
QFileInfo常规方法
postgresql源码学习(33)—— 事务日志⑨ - 从insert记录看日志写入整体流程
拓扑排序的两种方法 --- dfs+Kahn
文件 - 04 下载文件: 根据文件下载链接下载文件
Difficulty comparison between high concurrency and multithreading (easy to confuse)
数据库原理作业3 — JMU
SQL Server Datetime2数据类型
项目练习——备忘录(增删改查)
事务的四大特性
SCI写作指南
03-SDRAM:写操作(突发)
文件 - 03 下载文件:根据文件id获取下载链接
HuffmanTree
外贸网站优化-外贸网站优化教程-外贸网站优化软件
熟悉而陌生的新朋友——IAsyncDisposable
电压源的电路分析知识分享
在 ASP.NET Core 应用程序启动时运行代码的 3 种方法
机器学习反向传播的一些推导公式