PostgreSQL psql的使用,SQL语法,数据类型,递归SQL用法(四)|学习笔记

本文涉及的产品
云原生数据库 PolarDB PostgreSQL 版,标准版 2核4GB 50GB
云原生数据库 PolarDB MySQL 版,通用型 2核4GB 50GB
简介: 快速学习3 PostgreSQL psql的使用,SQL语法,数据类型,递归SQL用法(四)

开发者学堂课程【PostgreSQL快速入门:3 PostgreSQL psql的使用,SQL语法,数据类型,递归SQL用法(四)】学习笔记与课程紧密联系,让用户快速学习知识

课程地址https://developer.aliyun.com/learning/course/16/detail/89


3 PostgreSQL psql的使用,SQL语法,数据类型,递归SQL用法(四)

 

内容介绍

DML

、Query

练习

八、DML

INSERT

UPDATE

DELETE

个事务最大2^32条SQL(因为cmin,cmax的长度是4Bytes)一个事务中可以执行40条sql语句,cmin,cmax相当于事务中某一条sql语句的编号四个字节存储

PostgreSQL个事务中可以包含DML, DDL, DCL。

Begin

Drop table t

Rollback

t表还在可以放在事务里面

除了以下

create tablespace

create database

使用concurrently并行创建索引

其他未尽情况略

(Oracle执行DDL前自动将前面的未提交的事务提交,所以Oracle不支持在事务中执行DDL语句)

 

九、Query

1、JOIN

T1 CROSS JOIN T2 (T1 INNER JOIN T2 ON TRUE )

T1 [INNER]  LEFT RIGHT FULL ; [OUTER] , JOIN T2 ON boolean_ expression支持内部join还支持外部join

T1 [INNER] LEFT RIGHT FULL ; [OUTER] , JOIN T2 USING ( join column list )

T1 NATURAL  [INNER]  LEFT  RIGHT  FULL , [OUTER]  JOIN T2

The words INNER and OUTER are optional in all forms. INNER is the default; LEFT, RIGHT,and FULL imply an outer join.

减少sql的写法比如两个表的字段名相同类型相同的情况下可以用NATURAL join,NATURAL列刚好相同的字段时可以用NATURAL join

In the join只有两个表完全匹配时join才有输出left join左边的表跟右边的表没有任何匹配的情况下记录也可以输出

CROSS JOIN产生笛卡尔积不带任何条件两个表之间每一条都会有相互关系

当关联的两个表有两列同名同类型同长度,以下三种写法等同。

Natural inner join t1表和t2表有一个字段是相同的并且同名同类型就可以省掉 join的字段num跟Natural join一样

左或右连接,不满足条件的右或左表的值。

Left join t2 on t1,t1表的id等于2跟右边的number等于2没有匹配因为右边的表只有13,左边的表有123,关联时左边的表也会输出Right join也是一样t2表所有的字段跟t1表没有匹配时也有输出

全关联,不满足条件的值都置空。匹配的可以输出不匹配也能输出

2、ALIAS

table alias: 表的别名

FROM table_reference AS alias

FROM table_reference alias

colum alias:列的别名

SELECT expression [[ AS ] output_ name ]

subquery alias:只查询的别名

FROM (SELECT * FROM table1) AS alias_ name

3、Table as Function's Return data type作为表的返回类型

表或者函数返回的数据类型把一个表名作为函数的返回类型

return table's row type

create table t1 (id int,name text,crt_ time timestamp(o));创建表是t1

create or replace function f_ t1 (i_ id int) returns setof t1 as $$返回类型也可以指定t1,在创建一个表时默认创建跟表结构一样的复合数据类型

declare

begin

return query select * from t1 where id=i_id;直接把表返回也可以

return;

end;

$$ language plpgsql;

insert into t1 values(1,'digoal',now0);

insert into t1 values(1,'DIGOAL',now0);

select * fromf _t1(1);

id] nameI crt_ time

1 digoal I 2012-04-26 08:15:09

1 DIGOALI 2012-04-26 08:15:15

return composite type返回复合类型

create type type1 as (id int,name text,crt_time timestamp(o));创建复合类型跟t1表一样

create or replace function f_ type1 (i_id int) returns setof type1 as $$

declare

begin

return query select * from t1 where id=i_id;

return;

end;

$$ language plpgsql;

select * from f_ type1(1);

id I name I crt_ time

1 I digoal I 2012-04-26 08:15:09

1 I DIGOAL I 2012-04-26 08:15:15

return record 弹性数据类型可能有一个字段也可能有两个字段在弹性类型里面返回的时候输出的是什么结构

create or replace function f_ record1 (i_ id int) returns setof record as $$

declare

begin

return query select * from t1 where id=i _id;

return;

end;

$$ language plpgsql;

输出的是t1的数据类型写上对应t的框架

select * from f_ record1(1) as (id int,name text,crt_time timestamp(o));

id I Name I crt_ time

1 I digoal  I2012-04-26 08:15:09

1 I DIGOAL I 2012-04-26 08:15:15

4、GROUP BY [ HAVING ]

5、DISTINCT

SELECT DISTINCT setect_ list ... (NULL/EDISTINCT [ON]中视为相等)

postgres= # select * from t1 ;

id  name crt_ time

1 I digoal I 2012-04-26 08:15:09

1 I DIGOAL I 2012-04-26 08:15:15

postgres= # select distinct id from t1;

id

1

SELECT DISTINCT ON (expression [, expression .. ])select_ list ... -- ON()里面必须出现在order by中作为前导列,输出跟前导列相关的DISTINCT ON,同时输出其它的查询列可以简化使用窗口函数

Here expression is an arbitrary value expression that is evaluated for all rows. A set of rows for which all the expressions are equal are considered duplicates, and only the first row of the set is kept in the output. Note that the "first row" of a set is unpredictable unless the query is sorted on enough columns to guarantee a unique ordering of the rows arriving at the DISTINCT filter. (DISTINCT ON processing occurs after ORDER BY sorting.)

postgres= =# select distinct on (id)-id,name,crt_ time from t1 order by id,crt_ time;输出id是唯一的id只输出一个按照顺序进行排序只要拿到一条就返回,digoal查处消息排在第一位当id=1取到两条只会要第一条

Id  name crt_ time

1 digoal 2012-04-26 08:15:09

postgres= =# select distinct on (id) id,name,crt_ time from tl order by id,crt_ time desc;必须在前导列里

Id name crt_ time

1 DIGOAL  2012-04-2608:15:156、COMBINING QUERY

Id name也是一样要放在前面

使用DISTINCT ON实现用窗口函数实现的取第一名的功能

postgres=# CREATE TABLE window_ test(id int, name text, subject text, score numeric);创建表记录学生每一科的考试成绩插入15条记录每个学科取一个取出id取出name分数科目

postgres=# INSERT INTO window_ test VALUES (,digoal,'数学',99.5), (2,digoal,;语文',89.5),

(3,'digoal',英语',79.5), (4,digoal",;物理' ,9.5), (5,digoal;'化学',98.5),

(6,刘德华';数学,89.5), (7,刘德华',语文.,99.5), (8,刘德华,英语',79.5),

(9,刘德华,物理,89.5), (10,刘德华;化学',69.5),

(11,张学友,数学",89.5), (12,张学友,语文",91.5), (13,张学友,英语',92.5),

(14,张学友,物理",93.5), (15,;张学友,化学,94.5);

取出每门课程的第一名

postgres=# select distinct on (subject) jid,name,subject,score from window_test order by subject,score desc;排序按照倒叙

5 Digoal 化学98.5

1 Digoal 数学99.5

4 Digoal 物理99.5

13 张学友 英语92.5

7 刘德华 语文99.5

与使用窗口函数得到的结果一致, 并且写法更简洁

select = from <select row_number() over < partition by subject order by score desc> as rn, * from window test> as t where rn

=1;

5 Digoal 化学98.5

1 Digoal 数学99.5

4 Digoal 物理99.5

13 张学友 英语92.5

7 刘德华 语文99.5

合并查询两个查询的结果集合起来两个查询的结果集算出相交的部分第一个查询结果集排除掉第二个查询的结果集的一些结果

queryl UNION [ALL] query2 两个查询结果集合并并且去重

queryl INTERSECT [ALL] query2 两个结果集合并不用去重

queryl EXCEPT [ALL] query2

5"

UNION effectively appends the result of query2 to the result of 'queryl (although there is no guarantee that this is the order in which the rows are actually returned)

INTERSECT returns all rows that are both in the result of queryl and in the result of query2.两个查询共有的部分相交的部分输出并且去重all就不去重

EXCEPT returns all rows that are in the result of queryl but not in the result of 'query2.

Combining Query eliminates duplicate rows from its result, in the same way as DISTINCT,

I unless ALL is used

queryl and query2 must return the same number of columns and the corresponding columns

have compatible data types.

8、LIMIT [ OFFSET ]

SELECT select_ list

FROM table_ expression

ORDER BY sort_ expressionl [ASCIDESC] [NULLS { FIRST[LAST} ,]空放在最前面还是最后面

[, sort_ expression2 [ASC I DESC] [NULLS i FIRST LAST ]...]

限制多少行比如表只输出一行就只有一个offset10扫描到第十行之后只输出一行

9、函数三态简介

非常重要的函数三态

在prostgre里面函数有三个状态第一个跟函数本身有关第二个函数的三个状态对prostgre执行计划的优化器会拿来用优化器如果看到函数是超级稳定的状态比如immutable,在执行时对于同样的参数传入在sql语句里面即使扫描了多行也只会处理一遍,immutable类似于常量只会同样的参数传入只会传入一遍返回结果sql语句在执行时会大大减少运算量

immutable最稳定的状态

Stable第二稳定

Volatile最不稳定即使传入的参数是一样的输出的结果多次调用输出的结果可能不一样比如select-now函数多次调用输出的结果不一样对于常量的函数如果是StableVolatile在一次事务中多次执行的结果可能是一样的

创建一个序列seq

digoal=# create sequence seq;

CREATE SEQUENCE

取序列的下一个值最不稳定

digoal=# select provolatile from pg_ proc where proname = 'nextval';

在一次事务中不停的调用它得到的值是不一样的即使是在sql语句中调用它也是不一样的比如调用15条记录得到的值都是不一样的

provolatile

V

(1 row)

digoal=# select nextval('seq'::regclass) from generate_ _series(1,3);

Nextval

1

2

3

(3 rows)

改成immutable后只会执行一次优化器在解析sql时只会执行一次不管有多少条记录30条记录也只会执行一次

digoal=# alter function nextval(regclass) immutable;

ALTER FUNCTION

digoal=# select nextval('seq'::regclass) from generate_ series(1,3);

nextval

4

4

4

(3 rows)

digoal=#alter function nextval(regclass) stable;执行一次只不过放在查询里面和放在后面不一样

ALTER FUNCTION

digoal=# select nextval'seq':regclass) from generate_ series(1,3);

nextval

5

6

7

(3 rows)

在select子句和在where子句中有差别。

例如某个表有5条记录:

digoal=# select *from t;

Id

3

3

3

4

5

(5 rows)

对于stable态,它在select中,每条tuple都要运算到这个函数,但是在where子句中,只运算次。

select nextval<' seq' >from t;

select from t where nextval<' seq' >=138;只执行一遍三条记录都返回执行多遍只返回一条记录

select nextval<’seq'>;

nextval

142

where子句在selec字句中,stable有一定的区别跟解析有关系

stableimmutable的不同之处,immutable两遍都是一样的where字句中和查询字句中结果一样

stable函数在execute时执行

immutable函数在plan时执行

所以stableimmutable仅仅当使用planed query时才有区别

如果使用执行器绑定变量的查询Planed query属于一次plan多次execute,immutable在Planed query中也只会执行一次就是常量stable函数是在execute执行的在这种场景中是会执行多次的

immutable稳定性>stable>volatile

另一些需要注意的:

函数内有多条SQL时,例如

digoal=# Create or replace function f10 returns setof int as$$

declare

v_ id int;

begin

Forv_ id in select id from t loop

return next V_ id;

End loop;

在这之间如果t发生了变更并提交了,volatile函数能看到这个变更。

perform pg_sleep(10);在执行过程中每一个sql语句看到的不是一个

For v_ id in select id from t loop

return next v_id;

End loop;

Return;

End;

$$ language plpgsql strict volatile;

volatile处理每个SQL都是一个新的snapshot. Stable和immutable将调用函数时作为这个snapshot。

创建函数中间休息十秒钟返回int类型来自于t表休息十秒钟把t表id全部储存如果期间有过变更当前123,三条记录第一次取出的是前面几条第二次取出后面几条如果是在执行过程中delete就只会返回三条记录后面的变更也会看到t表已经没了如果把函数改成stable,再进行查询比如插入几条数据都看不到,0 rows使用volatile函数在整个里面不是镜像而是每一条sql语句都会产生pg_sleep隔离级别的类似的查询对于Stable和immutable函数停了10秒钟再查询看到的是调用函数的

Select=from f1() ;

多次调用和单词调用有区别当前状态改成immutable。

function f1<>immutable;

immutable函数只调用一次只会select10十秒之后就可以看到结果如果改成volatile,每一条就都会执行执行十次一百秒之后才会看到结果pg_sleep默认volatile执行三条记录会执行3如果改成immutable就只会执行一遍只需要一秒出结果。对于大运算量的函数,且一条sQL如果返回多值,并且传入的参数致的情况下. 调用次显然比调用多次耗费小。

实际使用过程中选择好三态是非常重要的。

10、WITH

as把查询作为一个表对两个表进行关联查询

WITH regional_ sales AS (

SELECT region, SUM(amount) AS total_ sales

FROM orders

GROUP BY region

),top_ regions AS ( 也可以是update查询数据后面再进行查询也可以

SELECT region

FROM regional sales

WHERE total_ sales > (SELECT SUM(total_ sales)/10 FROM regional_sales)

SELECT region,

product,

SUM(quantity) AS product_ units,

SUM(amount) AS product_ sales

FROM orders

WHERE region IN (SELECT region FROM(top_ regions)

GROUP BY region, product;

如果是递归查询使用valus

Valus(1)非递归字句

Union all 不去重Union去重

SELECT n+1 FROMt WHERE n< 100 递归字句

SELECT sum(n) FROM t;输出的结果做查询中间会产生临时存放的对象

UNION ALL去重复(去重复时NULL视为等同)

图中所有输出都涉及UNION[ALL]的操作,包含以往返回的记录和当前返回的记录

图表示如何做循环的从非递归子句开始输出放在output里面递归字句读取output同时输出到TEMP Working TABLe临时工作表里面会有判断如果临时工作表里面有数据它会进入递归再次调用递归子句递归子句会先把临时工作表的数据读出来进行关联递归子句里面有关联t是工作表where条件再次查询输出到TEMP immutable table替换掉twt的内容后清空自己递归子句执行后TEMP Working TABLe已经刷新了已经从TEMP immutable table刷到TEMP Working TABLe中表已经清掉如果TEMP Working TABLe中有数据又会进入循环如果没有数据就直接输出了在循环里面有第六步还做了输出递归子句从TEMP Working TABLe读数据同时会产生输出输出到output有合并的动作如果是UNION就会去重如果是UNION all就直接扔到output中如果在TEMP Working TABLe中一直有数据就会进入无限的循环

image.png

TEMP Working Table 没有ctid, cmin, cmax, xmin, xmax, tableoid虚拟字段如果有会报错

postgres=# create table test (id int,name text);

postgres=# insert into test values (1,'digoall),(2,'digoal2');

postgres=# begin;

postgres=# with t1 as (update test set name= ='DIGOAL2' where id=2 returning *)

select ctid from t1;

ERROR: column "ctid" does not exist

LINE 2: select ctid from t1;

postgres =# rollback;

其它字段(cmin,cmax,xmin,xmax,tableoid)同样错误

递归查询输出产品部以及该部门的所有子部门信息

然后输出各个子部门以及各个子部门的人数

第一次取出的表隐式使用中间表

WITH RECURSIVE included_ parts(sub_ part, part, quantity) AS (开头非递归子句

初始输出

SELECT sub_part, part, quantity FROM parts WHERE part=产品部’。子部门部门id人数

UNION ALL不去重

把第一个sql取到的值作关联

SELECT p.sub_ part, B:part, p.quantity循环sql

第一步时读取的是初始输出,后面都是TEMP Working TABLE

FROM included parts pr, parts p进行关联

WHERE p.part = pr.sub_ part部门等于子部门输出只要产品部输出之后就能关联到子部门sub就是r表父表父表的子部门等于p表的部门id输出第一个子部门输出完之后会放到临时工作表相当于产品部第一个子部门第一步循环到达再进行循环一直到两个字段不匹配,把所有的子部门都输出来在递归循环后面再做操作

)

SELECT sub_ part, SUM(quantity) as total quantity输出每一子部门的部门id和总人数

FROM included_ parts

GROUP BY sub_ part

死循环

image.png

每次递归输出的记录与以往的记录都不一样,TEMP Working Table永远都有记录,因此无限循环

规避上一个死循环的方法

让递归SQL有机会没记录输出

WITH RECURSIVE search_ graph(id, link, data, depth, path, cycle) AS (

SELECT g.id, g.link, g.data, 1,

ARRAY[g.id],

False 变成ture

FROM graph g

UNION ALL

SELECT g.id, g.link, g.data, sg.depth+ 1,

Path||g.id,

g.id = ANY(path)

FROM graph g, search_ graph sg

WHERE g.id = sg.link AND NOT cycle判断变成flase

SELECT * FROM search_ graph;

多值比较需使用ROW类型的ARRAY

WITH RECURSIVE search_ graph(id, link, data, depth, path, cycle) AS (

SELECT g.id, g.link, g.data, 1,

ARRAY[ROW(g.f1, g.f2)],

false

FROM graph g

UNION ALL

SELECT g.id, g.link, g.data, sg.depth+1,

path||ROW(g.f1, g.f2),

ROW(g.f1, g.f2)= ANY(path)相当于数组

FROM graph g, search_graph sg

WHERE g.id = sg.link AND NOT cycle

SELECT * FROM search_ graph;

还有什么情况可以跳出循环

WITH RECURSIVE t(n) AS(

SELECT 1

UNION ALL

SELECT n+1FROM t

SELECT n FROM t LIMIT 100;

注意如果t表在递归子句的外围被join了然后再limit的还死循环

使用递归查询注意防止死循环

把属于产品部以及它的子部门的记录删除跟第一个例子差不多

WITH RECURSIVE included_ parts(sub_ part, part) AS (

SELECT sub part, part FROM parts WHERE part = '产品部'

UNION ALL

SELECT p.sub_ part, p.part

FROM included_ parts pr, parts p

WHERE p.part = pr.sub_ part

)

DELETE FROM parts

WHERE part IN (SELECT part FROM included_ parts);

WITH的所有子句包括MAIN子句查看到的是一个SNAPSHOT拆成很多个sql语句看到的是同一个SNAPSHOT

各个子句对记录的变更相互看不到,如果要看到变更的数据需使用RETURNING子句比如update一些记录对于查询语句它看到的是update之前的记录并不是update之后的只有RETURNING *才会查产品表查t表看到更新后的记录否则看到的就是更新前的记录

WITH t AS(

UPDATE products SET price = price * 1.05 WHERE id= 10

RETURNING *

SELECT * FROM products WHERE id= 10;

WITH t AS (

UPDATE products SET price= price * 1.05 WHERE id= 10

RETURNING *

SELECT* FROM t;

测试表

postgres =# create table test (id int,name text);

CREATE TABLES

postgres= =# insert into test values(1,'digoall),(2,'digoal2');

这样会看到老数据

postgres= =# with t1 as (update test set name ='NEW' where id=2 returning *)

postgres-# select * from test where name ='NEW";

id name

(0 rows)

postgres= =# with t1 as (update test set name= ='NEWNEW" where id= 2 returning *)

postgres-# select * from t1 where name ='NEWNEW";

id name

2 I NEWNEW

(1 row)

 

十、练习

1、psqI的使用熟悉特别是psql的帮助对于使用会带来很大的便利性查看表结构查看表大小都可以查询比如创建extensions外部表

2、数据库基本操作练习,例如建表,表的操作,建立测试模型,使用pgbench测试

相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
相关文章
|
2月前
|
SQL 关系型数据库 C语言
PostgreSQL SQL扩展 ---- C语言函数(三)
可以用C(或者与C兼容,比如C++)语言编写用户自定义函数(User-defined functions)。这些函数被编译到动态可加载目标文件(也称为共享库)中并被守护进程加载到服务中。“C语言函数”与“内部函数”的区别就在于动态加载这个特性,二者的实际编码约定本质上是相同的(因此,标准的内部函数库为用户自定义C语言函数提供了丰富的示例代码)
|
3月前
|
SQL 存储 关系型数据库
PostgreSQL核心之SQL基础学习
PostgreSQL核心之SQL基础学习
45 3
|
3月前
|
SQL 安全 关系型数据库
PostgreSQL SQL注入漏洞(CVE-2018-10915)--处理
【8月更文挑战第8天】漏洞描述:PostgreSQL是一款自由的对象关系型数据库管理系统,支持多种SQL标准及特性。存在SQL注入漏洞,源于应用未有效验证外部输入的SQL语句,允许攻击者执行非法命令。受影响版本包括10.5及更早版本等。解决方法为升级PostgreSQL
256 2
|
3月前
|
SQL 关系型数据库 MySQL
SQL Server、MySQL、PostgreSQL:主流数据库SQL语法异同比较——深入探讨数据类型、分页查询、表创建与数据插入、函数和索引等关键语法差异,为跨数据库开发提供实用指导
【8月更文挑战第31天】SQL Server、MySQL和PostgreSQL是当今最流行的关系型数据库管理系统,均使用SQL作为查询语言,但在语法和功能实现上存在差异。本文将比较它们在数据类型、分页查询、创建和插入数据以及函数和索引等方面的异同,帮助开发者更好地理解和使用这些数据库。尽管它们共用SQL语言,但每个系统都有独特的语法规则,了解这些差异有助于提升开发效率和项目成功率。
364 0
|
SQL .NET 数据库连接
|
SQL 存储 数据库
SQL 语法大全
一、基础1、说明:创建数据库CREATEDATABASEdatabase-name 2、说明:删除数据库dropdatabase dbname3、说明:备份sql server--- 创建 备份数据的 deviceUSE masterEXEC sp_addumpd...
1581 0
|
2月前
|
关系型数据库 MySQL 网络安全
5-10Can't connect to MySQL server on 'sh-cynosl-grp-fcs50xoa.sql.tencentcdb.com' (110)")
5-10Can't connect to MySQL server on 'sh-cynosl-grp-fcs50xoa.sql.tencentcdb.com' (110)")
|
4月前
|
SQL 存储 监控
SQL Server的并行实施如何优化?
【7月更文挑战第23天】SQL Server的并行实施如何优化?
111 13
|
4月前
|
SQL
解锁 SQL Server 2022的时间序列数据功能
【7月更文挑战第14天】要解锁SQL Server 2022的时间序列数据功能,可使用`generate_series`函数生成整数序列,例如:`SELECT value FROM generate_series(1, 10)。此外,`date_bucket`函数能按指定间隔(如周)对日期时间值分组,这些工具结合窗口函数和其他时间日期函数,能高效处理和分析时间序列数据。更多信息请参考官方文档和技术资料。
|
4月前
|
SQL 存储 网络安全
关系数据库SQLserver 安装 SQL Server
【7月更文挑战第26天】
60 6