PostgreSQL教程(四):高级特性
一、简介
在之前的章节里我们已经涉及了使用SQL在PostgreSQL中存储和访问数据的基础知识。现在我们将要讨论SQL中一些更高级的特性,这些特性有助于简化管理和防止数据丢失或损坏。最后,我们还将介绍一些PostgreSQL扩展。
本章有时将引用教程(三)中的例子并对其进行改变或改进以便于阅读本章。本章中的某些例子可以在教程目录的advanced.sql
文件中找到。该文件也包含一些样例数据,在这里就不在赘述(查看教程(三)第一节了解如何使用该文件)。
二、视图
回想一下教程(三)第六节中的查询。假设天气记录和城市位置的组合列表对我们的应用有用,但我们又不想每次需要使用它时都敲入整个查询。我们可以在该查询上创建一个视图,这会给该查询一个名字,我们可以像使用一个普通表一样来使用它:
创建视图:CREATE VIEW myview AS SELECT city, temp_lo, temp_hi, prcp, date, location FROM weather, cities WHERE city = name;
查看当前数据库的表:\d
查询视图的数据:select * from myview;
对视图的使用是成就一个好的SQL数据库设计的关键方面。视图允许用户通过始终如一的接口封装的结构细节,这样可以避免表结构随着应用的进行而变化。
视图几乎可以用在任何可以使用表的地方。在其他视图基础上创建视图也并不少见。
三、外键
回想教程(三)中的weather和cities表。考虑以下问题:我们希望确保在cities表中有相应项之前任何人都不能在weather表中插入行。这叫做维持数据的引用完整性。在过分简化的数据库系统中,可以通过线检查cities表中是否有匹配的记录存在,然后决定应该接受还是拒绝即将插入weather表的行。这种方法有一些问题且并不方便,于是PostgreSQL可以为我们来解决。
新的表定义如下:
创建cities表:CREATE TABLE cities (city varchar(80) primary key,location point
);创建weather表:CREATE TABLE weather (city varchar(80) references cities(city),temp_lo int,temp_hi int,prcp real,date date
);查看表:\d
现在尝试插入一个非法的记录:
INSERT INTO weather VALUES ('Berkeley', 45, 53, 0.0, '1994-11-28');
报错信息为:
ERROR: insert or update on table "weather" violates foreign key constraint "weather_city_fkey"
DETAIL: Key (city)=(Berkeley) is not present in table "cities".
外键的行为可以很好地根据应用来调整。我们不会再这个教程里更深入地介绍,读者可以参考第 5 章中的信息。正确使用外键无疑会提高数据库应用的质量,因此强烈建议用户学会如何使用它们。
四、事务
事务是所有数据库系统的基础概念。事务最重要的一点是它将多个步骤捆绑成了一个单一的、要么全完成要么全不完成的操作。步骤之间的中间状态对于其他并发事务是不可见的,并且如果有某些错误发生导致事务不能完成,则其中任何一个步骤都不会对数据库造成影响。
例如,考虑一个保存着多个客户账户余额和支行总存款额的银行数据库。假设我们希望记录一笔从Alice的账户到Bob的账户的额度为100美金的转账。在最大程度地简化后,涉及到的SQL命令是:
UPDATE accounts SET balance = balance - 100.00WHERE name = 'Alice';
UPDATE branches SET balance = balance - 100.00WHERE name = (SELECT branch_name FROM accounts WHERE name = 'Alice');
UPDATE accounts SET balance = balance + 100.00WHERE name = 'Bob';
UPDATE branches SET balance = balance + 100.00WHERE name = (SELECT branch_name FROM accounts WHERE name = 'Bob');
这些命令的细节在这里并不重要,关键点是为了完成这个相当简单的操作涉及到多个独立的更新。我们的银行职员希望确保这些更新要么全部发生,或者全部不发生。当然不能发生因为系统错误导致Bob收到100美元而Alice并未被扣款的情况。Alice当然也不希望自己被扣款而Bob没有收到钱。我们需要一种保障,当操作中途某些错误发生时已经执行的步骤不会产生效果。将这些更新组织成一个事务就可以给我们这种保障。一个事务被称为是原子的:从其他事务的角度来看,它要么整个发生要么完全不发生。
我们同样希望能保证一旦一个事务被数据库系统完成并认可,它就被永久地记录下来且即便其后发生崩溃也不会被丢失。例如,如果我们正在记录Bob的一次现金提款,我们当然不希望他刚走出银行大门,对他账户的扣款就消失。一个事务型数据库保证一个事务在被报告为完成之前它所做的所有更新都被记录在持久存储(即磁盘)。
事务型数据库的另一个重要性质与原子更新的概念紧密相关:当多个事务并发运行时,每一个都不能看到其他事务未完成的修改。例如,如果一个事务正忙着总计所有支行的余额,它不会只包括Alice的支行的扣款而不包括Bob的支行的存款,或者反之。所以事务的全做或全不做并不只体现在它们对数据库的持久影响,也体现在它们发生时的可见性。一个事务所做的更新在它完成之前对于其他事务是不可见的,而之后所有的更新将同时变得可见。
在PostgreSQL中,开启一个事务需要将SQL命令用BEGIN
和COMMIT
命令包围起来。因此我们的银行事务看起来会是这样:
BEGIN;
UPDATE accounts SET balance = balance - 100.00WHERE name = 'Alice';
-- etc etc
COMMIT;
如果,在事务执行中我们并不想提交(或许是我们注意到Alice的余额不足),我们可以发出ROLLBACK命令,而不是COMMIT命令,这样所有目前的更新将会被取消。
PostgreSQL实际上将每一个SQL语句都作为一个事务来执行。如果我们没有发出BEGIN
命令,则每个独立的语句都会被加上一个隐式的BEGIN
以及(如果成功)COMMIT
来包围它。一组被BEGIN
和COMMIT
包围的语句也被称为一个事务块。
Notes:
某些客户端库会自动发出BEGIN和COMMIT命令,因此我们可能会在不被告知的情况下得到事务块的效果。具体请查看所使用的接口文档。
也可以利用保存点来以更细的粒度开控制一个事务中的语句。保存点允许我们有选择性地放弃事务的一部分而提交剩下的部分。在使用SAVEPOINT定义一个保存点后,我们可以在必要时利用ROLLBACK TO回滚到该保存点。该事务中位于保存点和回滚点之间的数据库修改都会被放弃,但是早于该保存点的修改则会被保存。
在回滚到保存点之后,它的定义依然存在,因此我们可以多次回滚到它。反过来,如果确定不再需要回滚到特定的保存点,它可以被释放以便系统释放一些资源。记住不管是释放保存点还是回滚到保存点都会释放定义在该保存点之后的所有其他保存点。
所有这些都发生在一个事务块内,因此这些对于其他数据库会话都不可见。当提交整个事务块时,被提交的动作将作为一个单元变得对其他会话可见,而被回滚的动作则永远不会变得可见。
记住那个银行数据库,假设我们从Alice的账户扣款100美元,然后存款到Bob的账户,结果直到最后才发现我们应该存到Wally的账户。我们可以通过使用保存点来做这件事:
BEGIN;
UPDATE accounts SET balance = balance - 100.00WHERE name = 'Alice';
SAVEPOINT my_savepoint;
UPDATE accounts SET balance = balance + 100.00WHERE name = 'Bob';
-- oops ... forget that and use Wally's account
ROLLBACK TO my_savepoint;
UPDATE accounts SET balance = balance + 100.00WHERE name = 'Wally';
COMMIT;
当然,这个例子是被过度简化的,但是在一个事务块中使用保存点存在很多种控制可能性。此外,ROLLBACK TO
是唯一的途径来重新控制一个由于错误被系统置为中断状态的事务块,而不是完全回滚它并重新启动。
五、窗口函数
一个窗口函数在一系列与当前行有某种关联的表行上执行一种计算。这与一个聚集函数所完成的计算有可比之处。但是窗口函数并不会使多行被聚集成一个单独的输出行,这与通常的非窗口聚集函数不同。取而代之,行保留它们独立的标识。在这些现象背后,窗口函数可以访问的不仅仅是查询结果的当前行。
下面是一个例子用于展示如何将每一个员工的薪水与他/她所在部门的平均薪水进行比较:
SELECT depname, empno, salary, avg(salary) OVER (PARTITION BY depname) FROM empsalary;
depname | empno | salary | avg -----------+-------+--------+-----------------------develop | 11 | 5200 | 5020.0000000000000000develop | 7 | 4200 | 5020.0000000000000000develop | 9 | 4500 | 5020.0000000000000000develop | 8 | 6000 | 5020.0000000000000000develop | 10 | 5200 | 5020.0000000000000000personnel | 5 | 3500 | 3700.0000000000000000personnel | 2 | 3900 | 3700.0000000000000000sales | 3 | 4800 | 4866.6666666666666667sales | 1 | 5000 | 4866.6666666666666667sales | 4 | 4800 | 4866.6666666666666667 (10 rows)
最开始的三个输出列直接来自于表empsalary,并且表中每一行都有一个输出行。第四列表示对与当前行具有相同depname值的所有表行取得平均值(这实际和非窗口avg聚集件数是相同的函数,但是OVER子句使得它被当做一个窗口函数处理并在一个格式的窗口帧上计算。)。
一个窗口函数调用总是包含一个直接跟在窗口函数名及其参数之后的OVER
子句。这使得它从句法上和一个普通函数或非窗口函数区分开来。OVER
子句决定究竟查询中的哪些行被分离出来由窗口函数处理。OVER
子句中的PARTITION BY
子句指定了将具有相同PARTITION BY
表达式值的行分到组或者分区。对于每一行,窗口函数都会在当前行同一分区的行上进行计算。
我们可以通过OVER
上的ORDER BY
控制窗口函数处理行的顺序(窗口的ORDER BY
并不一定要符合行输出的顺序。)。下面是一个例子:
SELECT depname, empno, salary,rank() OVER (PARTITION BY depname ORDER BY salary DESC) FROM empsalary;
depname | empno | salary | rank -----------+-------+--------+------develop | 8 | 6000 | 1develop | 10 | 5200 | 2develop | 11 | 5200 | 2develop | 9 | 4500 | 4develop | 7 | 4200 | 5personnel | 2 | 3900 | 1personnel | 5 | 3500 | 2sales | 1 | 5000 | 1sales | 4 | 4800 | 2sales | 3 | 4800 | 2 (10 rows)
如上所示,rank
函数在当前行的分区内按照ORDER BY
子句的顺序为每一个可区分的ORDER BY
值产生了一个数字等级。rank
不需要显式的参数,因为它的行为完全决定于OVER
子句。
一个窗口函数所考虑的行属于那些通过查询的FROM
子句产生并通过WHERE
、GROUP BY
、HAVING
过滤的“虚拟表”。例如,一个由于不满足WHERE
条件被删除的行是不会被任何窗口函数所见的。在一个查询中可以包含多个窗口函数,每个窗口函数都可以用不同的OVER
子句来按不同方式划分数据,但是它们都作用在由虚拟表定义的同一个行集上。
我们已经看到如果行的顺序不重要时ORDER BY
可以忽略。PARTITION BY
同样也可以被忽略,在这种情况下会产生一个包含所有行的分区。
SELECT salary, sum(salary) OVER () FROM empsalary;
salary | sum --------+-------5200 | 471005000 | 471003500 | 471004800 | 471003900 | 471004200 | 471004500 | 471004800 | 471006000 | 471005200 | 47100 (10 rows)
如上所示,由于在OVER
子句中没有ORDER BY
,窗口帧和分区一样,而如果缺少PARTITION BY
则和整个表一样。换句话说,每个合计都会在整个表上进行,这样我们为每一个输出行得到的都是相同的结果。但是如果我们加上一个ORDER BY
子句,我们会得到非常不同的结果:
SELECT salary, sum(salary) OVER (ORDER BY salary) FROM empsalary;
salary | sum --------+-------3500 | 35003900 | 74004200 | 116004500 | 161004800 | 257004800 | 257005000 | 307005200 | 411005200 | 411006000 | 47100 (10 rows)
这里的合计是从第一个(最低的)薪水一直到当前行,包括任何与当前行相同的行(注意相同薪水行的结果)。
窗口函数只允许出现在查询的SELECT
列表和ORDER BY
子句中。它们不允许出现在其他地方,例如GROUP BY
、HAVING
和WHERE
子句中。这是因为窗口函数的执行逻辑是在处理完这些子句之后。另外,窗口函数在非窗口聚集函数之后执行。这意味着可以在窗口函数的参数中包括一个聚集函数,但反过来不行。
如果需要在窗口计算执行后进行过滤或者分组,我们可以使用子查询。例如:
SELECT depname, empno, salary, enroll_date
FROM(SELECT depname, empno, salary, enroll_date,rank() OVER (PARTITION BY depname ORDER BY salary DESC, empno) AS posFROM empsalary) AS ss
WHERE pos < 3;
上述查询仅仅显示了内层查询中rank
低于3的结果。
当一个查询涉及到多个窗口函数时,可以将每一个分别写在一个独立的OVER
子句中。但如果多个函数要求同一个窗口行为时,这种做法是冗余的而且容易出错的。替代方案是,每一个窗口行为可以被放在一个命名的WINDOW
子句中,然后在OVER
中引用它。例如:
SELECT sum(salary) OVER w, avg(salary) OVER wFROM empsalaryWINDOW w AS (PARTITION BY depname ORDER BY salary DESC);
相关文章:

PostgreSQL教程(四):高级特性
一、简介 在之前的章节里我们已经涉及了使用SQL在PostgreSQL中存储和访问数据的基础知识。现在我们将要讨论SQL中一些更高级的特性,这些特性有助于简化管理和防止数据丢失或损坏。最后,我们还将介绍一些PostgreSQL扩展。 本章有时将引用教程࿰…...

168基于matlab的六自由度并联摇摆台的反解控制算法
基于matlab的六自由度并联摇摆台的反解控制算法,stewart平台,配有GUI界面,可以自定义角度,杆长等参数。设定动平台位姿即能得到电机参数。程序已调通,可直接运行。 168 六自由度并联摇摆台 反解控制算法 (xiaohongshu.…...

MDC 日志跟踪笔记
一、前言 本文主要解析应用中比较实在的一个log4j的链路应用,在经过一段时间的应用后发现还是很稳的,就记录一下这个MDC 代表Mapped Diagnostic Context(映射式诊断上下文)的情况。 Tisp: 它是一个线程安全的存放诊断日志的容器 T…...

MySQL错误-this is incompatible with sql_mode=only_full_group_by完美解决方案
项目场景 有时候,遇到数据库重复数据,需要将数据进行分组,并取出其中一条来展示,这时就需要用到group by语句。 但是,如果mysql是高版本,当执行group by时,select的字段不属于group by的字段的…...

人工智能|机器学习——基于机器学习的舌苔检测
代码下载: 基于深度学习的舌苔检测毕设留档.zip资源-CSDN文库 1 研究背景 1.1.研究背景与意义 目前随着人们生活水平的不断提高,对于中医主张的理念越来越认可,对中医的需求也越来越多。在诊断中,中医通过观察人的舌头的舌质、苔…...

SQL查询转化为 Elasticsearch 查询
使用SQL 转化为查询 Elasticsearch 支持 sql 语句转化为 elasticsearch 的 查询语句 第一步: 打开在线转换工具的网页,进入工具页面 第二步:在指定的输入框中输入需要转换的 sql 语句。 您学会了这么简单的办法...

目标检测教程视频指南大全
魔鬼面具-哔哩哔哩视频指南 必看干货系列(建议搞深度学习的小伙伴都看看,特别是图像相关) 深度学习常见实验问题与实验技巧(适用于所有模型,小白初学者必看!)还在迷茫深度学习中的改进实验应该从哪里开始改起的同学,一定要进来看看了!用自身…...

【Linux取经路】文件系统之重定向的实现原理
文章目录 一、再来理解重定向1.1 输出重定向效果演示1.2 重定向的原理1.3 dup21.4 输入重定向效果演示1.5 输入重定向代码实现 二、再来理解标准输出和标准错误2.1 同时对标准输出和标准错误进行重定向2.2 将标准输出和标准错误重定向到同一个文件 三、再看一切皆文件四、结语 …...

JAVA设计模式结构型模式
一、前言 java设计模式主要分为创建型模式,结构型模式和行为型模式。上一篇主要总结了行为型设计模式,本章总结,结构型模式。像创建型模式就不写了,比较简单。大概知道是工厂模式和建造者模式,原型模式就行࿰…...

第4讲引入JWT前后端交互
引入JWT前后端交互 Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519); JWT就是一段字符串,用来进行用户身份认证的凭证,该字符串分成三段【头部、载荷、签证】 后端接口测试&…...

基于Java的车辆租赁管理平台/租车系统
功能介绍 平台采用B/S结构,后端采用主流的Springboot框架进行开发,前端采用主流的Vue.js进行开发。 整个平台包括前台和后台两个部分。 前台功能包括:首页、车辆详情、车辆预订、用户中心模块。后台功能包括:车辆管理、分类管理…...

如何升级至ChatGPT Plus:快速指南,ChatGPT的秘密武器GPT4.0是什么?
提到 ChatGPT。想必大家都有所耳闻。自从 2022 年上线以来,就受到国内外狂热的追捧和青睐,上线2个月,月活突破1个亿!!! 而且还在持续上涨中。因为有很多人都在使用 ChatGPT 。无论是各大头条、抖音等 App、…...

【天衍系列 05】Flink集成KafkaSink组件:实现流式数据的可靠传输 高效协同
文章目录 01 KafkaSink 版本&导言02 KafkaSink 基本概念03 KafkaSink 工作原理1.初始化连接2.定义序列化模式3.创建KafkaSink算子4.创建数据源5.将数据流添加到KafkaSink6.内部工作机制 04 KafkaSink参数配置05 KafkaSink 应用依赖06 KafkaSink 快速入门6.1 包结构6.2 项目…...

深度学习之pytorch实现逻辑斯蒂回归
深度学习之pytorch实现逻辑斯蒂回归 解决的问题数学公式logiatic函数损失值 代码与线性回归代码的区别数据损失值构造回归的函数 结果分析 解决的问题 logistic 适用于分类问题,这里案例( y为0和1 ,0和 1 分别代表一类) 于解决二分类…...

有事休假店铺无人看守怎么办?智能远程视频监控系统保卫店铺安全
在春节期间,很多自营店主也得到了久违的假期,虽然很多店主都是长期在店铺中看守,但遇到春节这样的日子,多数人还是选择回乡休假。面对店主休假或有事不能管理店铺时,传统的监控虽然可以做到单一的监控,却仍…...

酷开科技 | 酷开系统壁纸模式,让过年更有氛围感!
在阵阵爆竹声中,家家户户都沉浸在浓浓的年味中。过年,是团圆,是温暖。团团圆圆的日子里,仪式感不可少,换上一张喜气洋洋的电视壁纸吧,寓意幸福一年又一年。打开酷开系统壁纸模式挑选一张年味十足的壁纸&…...

Docker中部署flink集群的两种方式
文章目录 一、概述二、准备工作三、方式一四、方式二1、准备配置文件2、执行 docker 命令 一、概述 本文将通过 2 种方式在 docker 中部署 flink standalone 集群,集群中共有 4 个节点,分别是 1 个 jobManager 节点和 3 个 taskManager 节点。方式一能快…...

八、计算机视觉-边界填充
文章目录 前言一、原理二、具体的实现 前言 在Python中使用OpenCV进行边界填充(也称为zero padding)是一种常见的图像处理操作,通常用于在图像周围添加额外的像素以便进行卷积或其他操作。下面是使用OpenCV进行边界填充的基本原理和方法 一…...

ffmpeg 硬件加速介绍
基于OS的硬件加速 Windows 参考[2],基于windows的硬件加速都是基于DirectX API,我们可以用ffmpeg -hwaccels查看当前环境支持的硬件加速接口,如下为windows上的执行ffmpeg --hwaccels的结果。 在linux上执行ffmpeg -hwaccels的结果如下: 可以看到windows上支持的硬件加速…...

【QT+QGIS跨平台编译】之三十九:【Exiv2+Qt跨平台编译】(一套代码、一套框架,跨平台编译)
文章目录 一、Exiv2介绍二、文件下载三、文件分析四、pro文件4.1 exiv2-xmp4.2 exiv2lib_int4.3 exiv2lib五、编译实践一、Exiv2介绍 Exiv2是一个开源的C++库,用于读取、编辑和写入图片和视频文件的元数据。它可以处理各种类型的元数据,包括EXIF、IPTC、XMP等。 元数据是与…...

术业有专攻!三防加固平板助力工业起飞
在日常使用中的商业电脑比较追求时效性,以市场定位做标准,内部元件只需满足一般要求就行,使用寿命比较短。而三防平板电脑是主要运用在复杂、恶劣的环境下所以在需求方面较高,需要保证产品在恶劣条件下正常使用,满足行业领域的需求…...

适合tiktok运营的云手机需要满足什么条件?
TikTok作为一款全球热门的社交媒体平台,具有无限的市场潜力。然而,卖家在运营过程中常常会面临到视频0播、账号被降权、限流等问题,甚至可能因为多人同时使用一个IP而导致封号的风险。为了规避这些问题,越来越多的卖家将目光投向了…...

微服务-微服务Nacos配置中心
1.1 配置中心架构 1.2 Config Client源码分析 配置中心核心接口ConfigService public class ConfigServerDemo {public static void main(String[] args) throws NacosException, InterruptedException {String serverAddr "localhost";String dataId "naco…...

配置Python环境及job运行的虚拟环境
1、配置Jenkins的Python环境:Manage Jnekins-Global Tool Configuration-Python 2、安装pyenv插件 此插件会给每个job都创建一个虚拟Python环境 安装后,在job config-build中选择 virtualenv builder build job的时候会自动在/opt/jenkins(node主机的…...

【Java】图解 JVM 垃圾回收(二):垃圾收集器、Full GC
图解 JVM 垃圾回收(二) 1.垃圾收集器1.1 内存分配与回收策略1.2 Serial 收集器1.3 Parallel Scavenge 收集器1.4 ParNew 收集器1.5 CMS 收集器1.6 G1 收集器 2.Full GC 的触发条件 1.垃圾收集器 Java 虚拟机提供了多种垃圾回收器,每种回收器…...

Opencv绘图之rectangle、circle、line、ellipse、Rect、RotatedRect、Point
OpenCV中提供了多种函数来在图像上绘制各种基本形状,如矩形、圆形、线条、椭圆等。同时,Rect和RotatedRect是用来表示矩形区域的类,它们在图像处理中非常有用,尤其是在需要定义和操作图像区域时。Point类用于表示二维空间中的一个…...

HTML 字符实体参考清单
前言 一些字符在 HTML 中是预留的,拥有特殊的含义,比如小于号‘<’用于定义 HTML 标签的开始。如果我们希望浏览器正确地显示这些字符,我们必须在 HTML 源码中插入字符实体。 字符实体有三部分:一个和号‘&’和一个实体名…...

设计模式二:代理模式
1、什么是动态代理 可能很多小伙伴首次接触动态代理这个名词的时候,或者是在面试过程中被问到动态代理的时候,不能很好的描述出来,动态代理到底是个什么高大上的技术。不方,其实动态代理的使用非常广泛,例如我们平常使…...

php使用get_browser()函数将移动端和pc端分开
首先,确保你的PHP版本支持get_browser函数。get_browser函数是PHP内置的函数,但需要配置php.ini文件中的browscap参数,指定一个浏览器配置文件。 下载浏览器配置文件。你可以从 https://download.csdn.net/download/bigorange1/88850695 下…...

更改WordPress作者存档链接author和Slug插件Edit Author Slug
WordPress默认所有用户的存档永久链接都是/author/username/,不管是管理员还是订阅者或贡献者或作者或编辑。如果你想要自定义用户存档链接,比如根据角色不同使用不一样的author,或者自定义作者链接中的用户名Slug,那么建议考虑使…...