PostgreSQL教程之SQL语言高级阶段学习

 

 

1,PostgreSQL 约束

PostgreSQL 约束用于规定表中的数据规则。

如果存在违反约束的数据行为,行为会被约束终止。

约束可以在创建表时规定(通过 CREATE TABLE 语句),或者在表创建之后规定(通过 ALTER TABLE 语句)。

约束确保了数据库中数据的准确性和可靠性。

约束可以是列级或表级。列级约束仅适用于列,表级约束被应用到整个表。

以下是在 PostgreSQL 中常用的约束。

  • NOT NULL:指示某列不能存储 NULL 值。
  • UNIQUE:确保某列的值都是唯一的。
  • PRIMARY Key:NOT NULL 和 UNIQUE 的结合。确保某列(或两个列多个列的结合)有唯一标识,有助于更容易更快速地找到表中的一个特定的记录。。
  • FOREIGN Key: 保证一个表中的数据匹配另一个表中的值的参照完整性。
  • CHECK: 保证列中的值符合指定的条件。
  • EXCLUSION :排他约束,保证如果将任何两行的指定列或表达式使用指定操作符进行比较,至少其中一个操作符比较将会返回 false 或空值。

NOT NULL 约束

默认情况下,列可以保存为 NULL 值。如果您不想某列有 NULL 值,那么需要在该列上定义此约束,指定在该列上不允许 NULL 值。

NULL 与没有数据是不一样的,它代表着未知的数据。

实例

下面实例创建了一张新表叫 employee,添加了 5 个字段,其中三个 ID,NAME,AGE 设置不接受空置:

runoobdb=# create table employee(id int primary key not null, name text not null, age int not null, address char(50), salary real);
CREATE TABLE

runoobdb=# select * from employee;
 id | name | age | address | salary 
----+------+-----+---------+--------
(0 rows)

runoobdb=# 

UNIQUE 约束

UNIQUE 约束可以设置列是唯一的,避免同一列出现重复值。

实例

下面实例创建了一张新表叫 employee1,添加了 5 个字段,其中 AGE 设置为 UNIQUE,因此你不能添加两条有相同年龄的记录:

runoobdb=# create table employee1(id int primary key not null, name text not null, age int not null unique, address char(50), salary real default 50000.00);
CREATE TABLE

runoobdb=# select * from employee1;                                              id | name | age | address | salary 
----+------+-----+---------+--------
(0 rows)

PRIMARY KEY

在设计数据库时,PRIMARY KEY 非常重要。

PRIMARY KEY 称为主键,是数据表中每一条记录的唯一标识。

设置 UNIQUE 的列可能有多个,但是一张表只有一列可以设置 PRIMARY KEY。

我们可以使用主键来引用表中的行,也可以通过把主键设置为其他表的外键,来创建表之间的关系。

主键是非空约束和唯一约束的组合。

一个表只能有一个主键,它可以由一个或多个字段组成,当多个字段作为主键,它们被称为复合键。

如果一个表在任何字段上定义了一个主键,那么在这些字段上不能有两个记录具有相同的值。

实例

下面我们创建 employee2 表,其中 ID 作为主键:

runoobdb=# create table employee2(id int primary key not null, name text not null,
CREATE TABLE

runoobdb=# select * from employee2;
 id | name | age | address | salary 
----+------+-----+---------+--------
(0 rows)

FOREIGN KEY 约束

FOREIGN KEY 即外键约束,指定列(或一组列)中的值必须匹配另一个表的某一行中出现的值。

通常一个表中的 FOREIGN KEY 指向另一个表中的 UNIQUE KEY(唯一约束的键),即维护了两个相关表之间的引用完整性。

实例

下面实例创建了一张 employee3表,并添加了5个字段:

runoobdb=# create table employee3(id int primary key not null, name text not null,
CREATE TABLE

runoobdb=# select * from employee3;
 id | name | age | address | salary 
----+------+-----+---------+--------
(0 rows)

下面实例创建一张 department表,并添加 3 个字段,EMP_ID 就是外键,参照 employee3 的 ID:

runoobdb=# create table department(id int primary key not null, dept char(50) not null, emp_id int references employee3(id));
CREATE TABLE

runoobdb=# select * from department;
 id | dept | emp_id 
----+------+--------
(0 rows)

CHECK 约束

CHECK 约束保证列中的所有值满足某一条件,即对输入一条记录要进行检查。如果条件值为 false,则记录违反了约束,且不能输入到表。

实例

例如,下面实例建一个新的表 employee4,增加了五列。在这里,我们为 SALARY 列添加 CHECK,所以工资不能为零:

runoobdb=# create table employee4(id int primary key not null, name text not null, age int not null, address char(50), salary real check(salary > 0));
CREATE TABLE

runoobdb=# select * from employee4;
 id | name | age | address | salary 
----+------+-----+---------+--------
(0 rows)

EXCLUSION 约束

EXCLUSION 约束确保如果使用指定的运算符在指定列或表达式上比较任意两行,至少其中一个运算符比较将返回 false 或 null。

实例

下面实例创建了一张 employee5 表,添加 5 个字段,并且使用了 EXCLUDE 约束。

runoobdb=# create extension btree_gist;
CREATE EXTENSION

runoobdb=# create table employee5(id int primary key not null, name text, age int, address char(50), salary real, EXCLUDE USING gist (name with =, age with <>));
CREATE TABLE

runoobdb=# \d
           List of relations
 Schema |    Name    | Type  |  Owner   
--------+------------+-------+----------
 public | company    | table | postgres
 public | company1   | table | postgres
 public | department | table | postgres
 public | employee   | table | postgres
 public | employee1  | table | postgres
 public | employee2  | table | postgres
 public | employee3  | table | postgres
 public | employee4  | table | postgres
 public | employee5  | table | postgres
(9 rows)

这里,USING gist 是用于构建和执行的索引一种类型。

您需要为每个数据库执行一次 CREATE EXTENSION btree_gist 命令,
这将安装 btree_gist 扩展,它定义了对纯标量数据类型的 EXCLUDE 约束。

由于我们已经强制执行了年龄必须相同,让我们通过向表插入记录来查看这一点:

runoobdb=# insert into employee5 values(1, 'Paul', 32, 'California', 20000.00);
INSERT 0 1

runoobdb=# insert into employee5 values(2, 'Paul', 32, 'Texas', 20000.00);
INSERT 0 1

runoobdb=# insert into employee5 values(3, 'Allen', 42, 'California', 20000.00);
INSERT 0 1

runoobdb=# insert into employee5 values(4, 'Allen', 52, 'California', 20000.00); 
ERROR:  conflicting key value violates exclusion constraint "employee5_name_age_excl"
DETAIL:  Key (name, age)=(Allen, 52) conflicts with existing key (name, age)=(Allen, 42).

 前面三条顺利添加的 employee5 表中,但是第四条则会报错。

ERROR:  conflicting key value violates exclusion constraint "employee6_name_age_excl"
DETAIL:  Key (name, age)=(Allen, 52) conflicts with existing key (name, age)=(Allen, 42).

删除约束

删除约束必须知道约束名称,已经知道名称来删除约束很简单,如果不知道名称,则需要找到系统生成的名称,使用 \d 表名 可以找到这些信息。

通用语法如下:

ALTER TABLE table_name DROP CONSTRAINT some_name;

2,PostgreSQL 连接(JOIN)

PostgreSQL JOIN 子句用于把来自两个或多个表的行结合起来,基于这些表之间的共同字段。

在 PostgreSQL 中,JOIN 有五种连接类型:

  • CROSS JOIN :交叉连接
  • INNER JOIN:内连接
  • LEFT OUTER JOIN:左外连接
  • RIGHT OUTER JOIN:右外连接
  • FULL OUTER JOIN:全外连接

接下来让我们创建两张表 COMPANY 和 DEPARTMENT

实例

创建 COMPANY 表,数据内容如下:

runoobdb=# select * from company;
 id | name  | age |                      address                       | salary | join_date  
----+-------+-----+----------------------------------------------------+--------+------------
  1 | Paul  |  32 | California                                         |  20000 | 2014-01-01
  2 | Allen |  25 | Texas                                              |  27500 | 2015-02-18
  3 | Teddy |  23 | Norway                                             |  18000 | 2016-03-28
  4 | Mark  |  25 | Rich-Mond                                          |   6500 | 2018-05-20
  5 | David |  27 | Texas                                              |  80500 | 2018-07-20
  6 | Kim   |  22 | South-Hall                                         |  40500 | 2019-07-10
  7 | James |  24 | Houston                                            |  10000 | 2017-03-02
  8 | Paul  |  24 | Houston                                            |  20000 | 2018-09-02
  9 | James |  44 | Norway                                             |   5000 | 2017-09-20
 10 | James |  45 | Texas                                              |   5000 | 2015-10-02
(10 rows)

创建一张 DEPARTMENT 表,添加三个字段:

runoobdb=# create table departments(id int primary key not null,dept char(50) not null, emp_id int not null);
CREATE TABLE

向 departments 表插入三条记录:

runoobdb=# insert into departments (id, dept, emp_id) values(1, 'IT Billing', 1);
INSERT 0 1
runoobdb=# insert into departments (id, dept, emp_id) values(2, 'Engineering', 2);
INSERT 0 1
runoobdb=# insert into departments (id, dept, emp_id) values(3, 'Finance', 7);
INSERT 0 1

此时,departments 表的记录如下:

runoobdb=# select * from departments;
 id |                        dept                        | emp_id 
----+----------------------------------------------------+--------
  1 | IT Billing                                         |      1
  2 | Engineering                                        |      2
  3 | Finance                                            |      7
(3 rows)

交叉连接

交叉连接(CROSS JOIN)把第一个表的每一行与第二个表的每一行进行匹配。如果两个输入表分别有 x 和 y 行,则结果表有 x*y 行。

由于交叉连接(CROSS JOIN)有可能产生非常大的表,使用时必须谨慎,只在适当的时候使用它们。

下面是 CROSS JOIN 的基础语法: 

SELECT ... FROM table1 CROSS JOIN table2 ...

基于上面的表,我们可以写一个交叉连接(CROSS JOIN),如下所示:

runoobdb=# SELECT EMP_ID, NAME, DEPT FROM COMPANY CROSS JOIN DEPARTMENT;

得到结果如下:

runoobdb=# select emp_id, name, dept from company cross join departments;
 emp_id | name  |                        dept                        
--------+-------+----------------------------------------------------
      1 | Paul  | IT Billing                                        
      1 | Allen | IT Billing                                        
      1 | Teddy | IT Billing                                        
      1 | Mark  | IT Billing                                        
      1 | David | IT Billing                                        
      1 | Kim   | IT Billing                                        
      1 | James | IT Billing                                        
      1 | Paul  | IT Billing                                        
      1 | James | IT Billing                                        
      1 | James | IT Billing                                        
      2 | Paul  | Engineering                                       
      2 | Allen | Engineering                                       
      2 | Teddy | Engineering                                       
      2 | Mark  | Engineering                                       
      2 | David | Engineering                                       
      2 | Kim   | Engineering                                       
      2 | James | Engineering                                       
      2 | Paul  | Engineering                                       
      2 | James | Engineering                                       
      2 | James | Engineering                                       
      7 | Paul  | Finance                                           
      7 | Allen | Finance                                           
      7 | Teddy | Finance                                           
      7 | Mark  | Finance                                           
      7 | David | Finance                                           
      7 | Kim   | Finance                                           
      7 | James | Finance                                           
      7 | Paul  | Finance                                           
      7 | James | Finance                                           
      7 | James | Finance                                           
(30 rows)

内连接

内连接(INNER JOIN)根据连接谓词结合两个表(table1 和 table2)的列值来创建一个新的结果表。查询会把 table1 中的每一行与 table2 中的每一行进行比较,找到所有满足连接谓词的行的匹配对。

当满足连接谓词时,A 和 B 行的每个匹配对的列值会合并成一个结果行。

内连接(INNER JOIN)是最常见的连接类型,是默认的连接类型。

INNER 关键字是可选的。

下面是内连接(INNER JOIN)的语法:

SELECT table1.column1, table2.column2...
FROM table1
INNER JOIN table2
ON table1.common_filed = table2.common_field;

基于上面的表,我们可以写一个内连接,如下所示:

runoobdb=# select emp_id, name, dept from company inner join departments on company.id = departments.emp_id;
 emp_id | name  |                        dept                        
--------+-------+----------------------------------------------------
      1 | Paul  | IT Billing                                        
      2 | Allen | Engineering                                       
      7 | James | Finance                                           
(3 rows)

左外连接

外部连接是内部连接的扩展。SQL 标准定义了三种类型的外部连接: LEFT、RIGHT 和 FULL, PostgreSQL 支持所有这些。

对于左外连接,首先执行一个内连接。然后,对于表 T1 中不满足表 T2 中连接条件的每一行,其中 T2 的列中有 null 值也会添加一个连接行。因此,连接的表在 T1 中每一行至少有一行。

下面是左外连接( LEFT OUTER JOIN )的基础语法:

SELECT ... FROM table1 LEFT OUTER JOIN table2 ON conditional_expression ...

基于上面两张表,我们可以写个左外连接,如下:

runoobdb=# select emp_id, name, dept from company left outer join departments on company.id = departments.emp_id;
 emp_id | name  |                        dept                        
--------+-------+----------------------------------------------------
      1 | Paul  | IT Billing                                        
      2 | Allen | Engineering                                       
      7 | James | Finance                                           
        | James | 
        | David | 
        | Paul  | 
        | Kim   | 
        | Mark  | 
        | Teddy | 
        | James | 
(10 rows)

右外连接

首先,执行内部连接。然后,对于表T2中不满足表T1中连接条件的每一行,其中T1列中的值为空也会添加一个连接行。这与左联接相反;对于T2中的每一行,结果表总是有一行。

下面是右外连接( RIGHT OUT JOIN)的基本语法:

SELECT ... FROM table1 RIGHT OUTER JOIN table2 ON conditional_expression ...

基于上面两张表,我们建立一个右外连接:

runoobdb=# select emp_id, name, dept from company right outer join departments on company.id = departments.emp_id;
 emp_id | name  |                        dept                        
--------+-------+----------------------------------------------------
      1 | Paul  | IT Billing                                        
      2 | Allen | Engineering                                       
      7 | James | Finance                                           
(3 rows)

外连接

首先,执行内部连接。然后,对于表 T1 中不满足表 T2 中任何行连接条件的每一行,如果 T2 的列中有 null 值也会添加一个到结果中。此外,对于 T2 中不满足与 T1 中的任何行连接条件的每一行,将会添加 T1 列中包含 null 值的到结果中。

下面是外连接的基本语法:

SELECT ... FROM table1 FULL OUTER JOIN table2 ON conditional_expression ...

基于上面两张表,可以建立一个外连接:

runoobdb=# select emp_id, name, dept from company full outer join departments on company.id = departments.emp_id;
 emp_id | name  |                        dept                        
--------+-------+----------------------------------------------------
      1 | Paul  | IT Billing                                        
      2 | Allen | Engineering                                       
      7 | James | Finance                                           
        | James | 
        | David | 
        | Paul  | 
        | Kim   | 
        | Mark  | 
        | Teddy | 
        | James | 
(10 rows)

3,PostgreSQL UNION 操作符

PostgreSQL UNION 操作符合并两个或多个 SELECT 语句的结果。

UNION 操作符用于合并两个或多个 SELECT 语句的结果集。

请注意,UNION 内部的每个 SELECT 语句必须拥有相同数量的列。列也必须拥有相似的数据类型。同时,每个 SELECT 语句中的列的顺序必须相同。

语法

UNIONS 基础语法如下:

SELECT column1 [, column2 ]
FROM table1 [, table2 ]
[WHERE condition]

UNION

SELECT column1 [, column2 ]
FROM table1 [, table2 ]
[WHERE condition]

这里的条件语句可以根据您的需要设置任何表达式。

实例

创建 COMPANY 表,数据内容如下:

runoobdb=# select * from company;
 id | name  | age |                      address                       | salary | join_date  
----+-------+-----+----------------------------------------------------+--------+------------
  1 | Paul  |  32 | California                                         |  20000 | 2014-01-01
  2 | Allen |  25 | Texas                                              |  27500 | 2015-02-18
  3 | Teddy |  23 | Norway                                             |  18000 | 2016-03-28
  4 | Mark  |  25 | Rich-Mond                                          |   6500 | 2018-05-20
  5 | David |  27 | Texas                                              |  80500 | 2018-07-20
  6 | Kim   |  22 | South-Hall                                         |  40500 | 2019-07-10
  7 | James |  24 | Houston                                            |  10000 | 2017-03-02
  8 | Paul  |  24 | Houston                                            |  20000 | 2018-09-02
  9 | James |  44 | Norway                                             |   5000 | 2017-09-20
 10 | James |  45 | Texas                                              |   5000 | 2015-10-02
(10 rows)

创建 DEPARTMENTS表,数据内容如下:

runoobdb=# select * from departments;
 id |                        dept                        | emp_id 
----+----------------------------------------------------+--------
  1 | IT Billing                                         |      1
  2 | Engineering                                        |      2
  3 | Finance                                            |      7
  4 | Engineering                                        |      3
  5 | Finance                                            |      4
  6 | Engineering                                        |      5
  7 | Finance                                            |      6
(7 rows)

现在,我们在 SELECT 语句中使用 UNION 子句将两张表连接起来,如下所示:

select emp_id, name, dept from company inner join departments on company.id = departments.emp_id union select emp_id, name, dept from company left outer join departments on company.id = departments.emp_id;

得到结果如下:

 emp_id | name  |                        dept                        
--------+-------+----------------------------------------------------
      7 | James | Finance                                           
      6 | Kim   | Finance                                           
      2 | Allen | Engineering                                       
      3 | Teddy | Engineering                                       
      5 | David | Engineering                                       
      4 | Mark  | Finance                                           
        | James | 
      1 | Paul  | IT Billing                                        
        | Paul  | 
(9 rows)

两个语句分开执行的结果如下:

runoobdb=# select emp_id, name, dept from company inner join departments on company.id = departments.emp_id;
 emp_id | name  |                        dept                        
--------+-------+----------------------------------------------------
      1 | Paul  | IT Billing                                        
      2 | Allen | Engineering                                       
      7 | James | Finance                                           
      3 | Teddy | Engineering                                       
      4 | Mark  | Finance                                           
      5 | David | Engineering                                       
      6 | Kim   | Finance                                           
(7 rows)
runoobdb=# select emp_id, name, dept from company left outer join departments on company.id = departments.emp_id; 
 emp_id | name  |                        dept                        
--------+-------+----------------------------------------------------
      1 | Paul  | IT Billing                                        
      2 | Allen | Engineering                                       
      7 | James | Finance                                           
      3 | Teddy | Engineering                                       
      4 | Mark  | Finance                                           
      5 | David | Engineering                                       
      6 | Kim   | Finance                                           
        | James | 
        | Paul  | 
        | James | 
(10 rows)

UNION ALL 子句

UNION ALL 操作符可以连接两个有重复行的 SELECT 语句,默认地,UNION 操作符选取不同的值。如果允许重复的值,请使用 UNION ALL。

语法

UINON ALL 子句基础语法如下:

SELECT column1 [, column2 ]
FROM table1 [, table2 ]
[WHERE condition]

UNION ALL

SELECT column1 [, column2 ]
FROM table1 [, table2 ]
[WHERE condition]

这里的条件语句可以根据您的需要设置任何表达式。

实例

现在,让我们把上面提到的两张表用 SELECT 语句结合 UNION ALL 子句连接起来:

runoobdemp_id, name, dept from company inner join departments on company.id = departments.emp_id union all select emp_id, name, dept from company left outer join departments on company.id = departments.emp_id;

得到结果如下:

 emp_id | name  |                        dept                        
--------+-------+----------------------------------------------------
      1 | Paul  | IT Billing                                        
      2 | Allen | Engineering                                       
      7 | James | Finance                                           
      3 | Teddy | Engineering                                       
      4 | Mark  | Finance                                           
      5 | David | Engineering                                       
      6 | Kim   | Finance                                           
      1 | Paul  | IT Billing                                        
      2 | Allen | Engineering                                       
      7 | James | Finance                                           
      3 | Teddy | Engineering                                       
      4 | Mark  | Finance                                           
      5 | David | Engineering                                       
      6 | Kim   | Finance                                           
        | James | 
        | Paul  | 
        | James | 
(17 rows)

4,PostgreSQL NULL 值

NULL 值代表遗漏的未知数据。

默认地,表的列可以存放 NULL 值。

本章讲解 IS NULL 和 IS NOT NULL 操作符。

语法

当创建表时,NULL 的基本语法如下:

runoobdb=# create table company2(
             id int primary key not null, 
             name text not null, 
             age int not null, 
             address char(50), 
             salary real);
CREATE TABLE

runoobdb=# select * from company2;
 id | name | age | address | salary 
----+------+-----+---------+--------
(0 rows)

这里,NOT NULL 表示强制字段始终包含值。这意味着,如果不向字段添加值,就无法插入新记录或者更新记录。

具有 NULL 值的字段表示在创建记录时可以留空。

在查询数据时,NULL 值可能会导致一些问题,因为一个未知的值去与其他任何值比较,结果永远是未知的。

另外无法比较 NULL 和 0,因为它们是不等价的。

在数据表中插入相关的数据并读取数据。

runoobdb=# insert into company2 values(1, 'Paul', 32, 'California', 20000);

runoobdb=# insert into company2 values(2, 'Allen', 25, 'Texas', 15000);

runoobdb=# insert into company2 values(3, 'Teddy', 23, 'Norway', 20000);

runoobdb=# insert into company2 values(4, 'Mark', 25, 'Rich-Mond', 65000);

runoobdb=# insert into company2 values(5, 'David', 27, 'Texas', 85000);

runoobdb=# insert into company2 values(6, 'Kim', 22, 'South-Hall', 45000);

runoobdb=# insert into company2 values(7, 'James', 24, 'Houston', 10000);
INSERT 0 1

runoobdb=# select * from company2;
 id | name  | age |                      address                       | salary 
----+-------+-----+----------------------------------------------------+--------
  1 | Paul  |  32 | California                                         |  20000
  2 | Allen |  25 | Texas                                              |  15000
  3 | Teddy |  23 | Norway                                             |  20000
  4 | Mark  |  25 | Rich-Mond                                          |  65000
  5 | David |  27 | Texas                                              |  85000
  6 | Kim   |  22 | South-Hall                                         |  45000
  7 | James |  24 | Houston                                            |  10000
(7 rows)

接下来我们用 UPDATE 语句把几个可设置为空的字段设置为 NULL :

runoobdb=# update company2 set address=null, salary=null where id in(6,7);
UPDATE 2

runoobdb=# select * from company2;
 id | name  | age |                      address                       | salary 
----+-------+-----+----------------------------------------------------+--------
  1 | Paul  |  32 | California                                         |  20000
  2 | Allen |  25 | Texas                                              |  15000
  3 | Teddy |  23 | Norway                                             |  20000
  4 | Mark  |  25 | Rich-Mond                                          |  65000
  5 | David |  27 | Texas                                              |  85000
  6 | Kim   |  22 |                                                    |       
  7 | James |  24 |                                                    |       
(7 rows)

IS NOT NULL

现在,我们用 IS NOT NULL 操作符把所有 SALARY(薪资) 值不为空的记录列出来:

runoobdb=# select id, age, address, salary from company2 where salary is not null;
 id | age |                      address                       | salary 
----+-----+----------------------------------------------------+--------
  1 |  32 | California                                         |  20000
  2 |  25 | Texas                                              |  15000
  3 |  23 | Norway                                             |  20000
  4 |  25 | Rich-Mond                                          |  65000
  5 |  27 | Texas                                              |  85000
(5 rows)

IS NULL

IS NULL 用来查找为 NULL 值的字段。

下面是 IS NULL 操作符的用法,列出 SALARY(薪资) 值为空的记录:

runoobdb=# select id, age, address, salary from company2 where salary is null; 
 id | age | address | salary 
----+-----+---------+--------
  6 |  22 |         |       
  7 |  24 |         |       
(2 rows)

5,PostgreSQL 别名

我们可以用 SQL 重命名一张表或者一个字段的名称,这个名称就叫着该表或该字段的别名。

创建别名是为了让表名或列名的可读性更强。

SQL 中 使用 AS 来创建别名。

语法

表的别名语法:

SELECT column1, column2....
FROM table_name AS alias_name
WHERE [condition];

列的别名语法:

SELECT column_name AS alias_name
FROM table_name
WHERE [condition];

实例

创建 COMPANY 表,数据内容如下:


runoobdb=# select * from company2;                                               id | name  | age |                      address                       | salary 
----+-------+-----+----------------------------------------------------+--------
  1 | Paul  |  32 | California                                         |  20000
  2 | Allen |  25 | Texas                                              |  15000
  3 | Teddy |  23 | Norway                                             |  20000
  4 | Mark  |  25 | Rich-Mond                                          |  65000
  5 | David |  27 | Texas                                              |  85000
  6 | Kim   |  22 | South-Hall                                         |  45000
  7 | James |  24 | Houston                                            |  10000
(7 rows)

创建 DEPARTMENTS表,数据内容如下:

runoobdb=# select * from departments;
 id |                        dept                        | emp_id 
----+----------------------------------------------------+--------
  1 | IT Billing                                         |      1
  2 | Engineering                                        |      2
  3 | Finance                                            |      7
  4 | Engineering                                        |      3
  5 | Finance                                            |      4
  6 | Engineering                                        |      5
  7 | Finance                                            |      6
(7 rows)

下面我们分别用 C 和 D 表示 COMPANY 表和 DEPAERMENT 表的别名:

runoobdb=# select c.id, c.name, c.age, d.dept from company2 as c, departments as d where c.id = d.emp_id;
 id | name  | age |                        dept                        
----+-------+-----+----------------------------------------------------
  1 | Paul  |  32 | IT Billing                                        
  2 | Allen |  25 | Engineering                                       
  7 | James |  24 | Finance                                           
  3 | Teddy |  23 | Engineering                                       
  4 | Mark  |  25 | Finance                                           
  5 | David |  27 | Engineering                                       
  6 | Kim   |  22 | Finance                                           
(7 rows)

下面,我们用 COMPANY_ID 表示 ID 列,COMPANY_NAME 表示 NAME 列,来展示列别名的用法:

runoobdb=# select c.id as company_id, c.name as company_name, c.age, d.dept from company2 as c, departments as d where c.id = d.emp_id;
 company_id | company_name | age |                        dept                        
------------+--------------+-----+----------------------------------------------------
          1 | Paul         |  32 | IT Billing                                        
          2 | Allen        |  25 | Engineering                                       
          7 | James        |  24 | Finance                                           
          3 | Teddy        |  23 | Engineering                                       
          4 | Mark         |  25 | Finance                                           
          5 | David        |  27 | Engineering                                       
          6 | Kim          |  22 | Finance                                           
(7 rows)

6,PostgreSQL 触发器

PostgreSQL 触发器是数据库的回调函数,它会在指定的数据库事件发生时自动执行/调用。

下面是关于 PostgreSQL 触发器几个比较重要的点:

  • PostgreSQL 触发器可以在下面几种情况下触发:

    • 在执行操作之前(在检查约束并尝试插入、更新或删除之前)。
    • 在执行操作之后(在检查约束并插入、更新或删除完成之后)。
    • 更新操作(在对一个视图进行插入、更新、删除时)。
  • 触发器的 FOR EACH ROW 属性是可选的,如果选中,当操作修改时每行调用一次;相反,选中 FOR EACH STATEMENT,不管修改了多少行,每个语句标记的触发器执行一次。

  • WHEN 子句和触发器操作在引用 NEW.column-name 和 OLD.column-name 表单插入、删除或更新时可以访问每一行元素。其中 column-name 是与触发器关联的表中的列的名称。

  • 如果存在 WHEN 子句,PostgreSQL 语句只会执行 WHEN 子句成立的那一行,如果没有 WHEN 子句,PostgreSQL 语句会在每一行执行。

  • BEFORE 或 AFTER 关键字决定何时执行触发器动作,决定是在关联行的插入、修改或删除之前或者之后执行触发器动作。

  • 要修改的表必须存在于同一数据库中,作为触发器被附加的表或视图,且必须只使用 tablename,而不是 database.tablename。

  • 当创建约束触发器时会指定约束选项。这与常规触发器相同,只是可以使用这种约束来调整触发器触发的时间。当约束触发器实现的约束被违反时,它将抛出异常。

语法

创建触发器时的基础语法如下:

CREATE  TRIGGER trigger_name [BEFORE|AFTER|INSTEAD OF] event_name
ON table_name
[
 -- 触发器逻辑....
];

在这里,event_name 可以是在所提到的表 table_name 上的 INSERT、DELETE 和 UPDATE 数据库操作。您可以在表名后选择指定 FOR EACH ROW。

以下是在 UPDATE 操作上在表的一个或多个指定列上创建触发器的语法:

CREATE  TRIGGER trigger_name [BEFORE|AFTER] UPDATE OF column_name
ON table_name
[
 -- 触发器逻辑....
];

实例

让我们假设一个情况,我们要为被插入到新创建的 COMPANY 表(如果已经存在,则删除重新创建)中的每一个记录保持审计试验:

runoobdb=# create table company(
                        id int primary key not null, 
                        name text not null,
                        age int not null,
                        address char(50), 
                        salary real);

CREATE TABLE

为了保持审计试验,我们将创建一个名为 AUDIT 的新表。每当 COMPANY 表中有一个新的记录项时,日志消息将被插入其中:

runoobdb=# create table audit(emp_id int not null, entry_date text null);
CREATE TABLE

在这里,ID 是 AUDIT 记录的 ID,EMP_ID 是来自 COMPANY 表的 ID,DATE 将保持 COMPANY 中记录被创建时的时间戳。所以,现在让我们在 COMPANY 表上创建一个触发器,如下所示:

runoobdb=# CREATE TRIGGER example_trigger AFTER INSERT ON COMPANY FOR EACH ROW EXECUTE PROCEDURE auditlogfunc();

auditlogfunc() 是 PostgreSQL 一个程序,其定义如下:

CREATE OR REPLACE FUNCTION auditlogfunc() RETURNS TRIGGER AS $example_table$
   BEGIN
      INSERT INTO AUDIT(EMP_ID, ENTRY_DATE) VALUES (new.ID, current_timestamp);
      RETURN NEW;
   END;
$example_table$ LANGUAGE plpgsql;

现在,我们开始往 COMPANY 表中插入数据:

runoobdb=# INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY) VALUES (2, 'Paul', 32, 'California', 30000.00 );

这时,COMPANY 表中插入了一条记录:

同时, AUDIT 表中也插入了一条记录,因为我们在插入 COMPANY 表时创建了一个触发器。相似的,我们也可以根据需求在更新和删除时创建触发器:

runoobdb=# select * from audit;                                                  
emp_id  |          entry_date           
--------+-------------------------------
      2 | 2020-06-20 17:40:31.780016+08
(1 row)

列出触发器

你可以把从 pg_trigger 表中把当前数据库所有触发器列举出来:

runoobdb=# SELECT * FROM pg_trigger;

结果如下:

  oid  | tgrelid |            tgname            | tgfoid | tgtype | tgenabled | tgisinternal | tgconstrrelid | tgconstrindid | tgconstraint | tgdeferrable | tginitdeferred | tgnargs | tgattr | tgargs | tgqual | tgoldtable | tgnewtable 
-------+---------+------------------------------+--------+--------+-----------+--------------+---------------+---------------+--------------+--------------+----------------+---------+--------+--------+--------+------------+------------
 16478 |   16464 | RI_ConstraintTrigger_a_16478 |   1654 |      9 | O         | t            |         16472 |         16470 |        16477 | f            | f              |       0 |        | \x     |        |            | 
 16479 |   16464 | RI_ConstraintTrigger_a_16479 |   1655 |     17 | O         | t            |         16472 |         16470 |        16477 | f            | f              |       0 |        | \x     |        |            | 
 16480 |   16472 | RI_ConstraintTrigger_c_16480 |   1644 |      5 | O         | t            |         16464 |         16470 |        16477 | f            | f              |       0 |        | \x     |        |            | 
 16481 |   16472 | RI_ConstraintTrigger_c_16481 |   1645 |     17 | O         | t            |         16464 |         16470 |        16477 | f            | f              |       0 |        | \x     |        |            | 
 17195 |   17180 | example_trigger              |  17194 |      5 | O         | f            |             0 |             0 |            0 | f            | f              |       0 |        | \x     |        |            | 
(5 rows)

如果,你想列举出特定表的触发器,语法如下:

runoobdb=# SELECT tgname FROM pg_trigger, pg_class WHERE tgrelid=pg_class.oid AND relname='company';

得到结果如下:

     tgname      
-----------------
 example_trigger
(1 row)

删除触发器

删除触发器基础语法如下:

drop trigger ${trigger_name} on ${table_of_trigger_dependent};

删除本文上表 company 上的触发器 example_trigger 的指令为:

drop trigger example_trigger on company;

7,PostgreSQL 索引

索引是加速搜索引擎检索数据的一种特殊表查询。简单地说,索引是一个指向表中数据的指针。一个数据库中的索引与一本书的索引目录是非常相似的。

拿汉语字典的目录页(索引)打比方,我们可以按拼音、笔画、偏旁部首等排序的目录(索引)快速查找到需要的字。

索引有助于加快 SELECT 查询和 WHERE 子句,但它会减慢使用 UPDATE 和 INSERT 语句时的数据输入。索引可以创建或删除,但不会影响数据。

使用 CREATE INDEX 语句创建索引,它允许命名索引,指定表及要索引的一列或多列,并指示索引是升序排列还是降序排列。

索引也可以是唯一的,与 UNIQUE 约束类似,在列上或列组合上防止重复条目。

CREATE INDEX 命令

CREATE INDEX (创建索引)的语法如下:

CREATE INDEX index_name ON table_name;

索引类型

单列索引

单列索引是一个只基于表的一个列上创建的索引,基本语法如下:

CREATE INDEX index_name ON table_name (column_name);

组合索引

组合索引是基于表的多列上创建的索引,基本语法如下:

CREATE INDEX index_name ON table_name (column1_name, column2_name);

不管是单列索引还是组合索引,该索引必须是在 WHEHE 子句的过滤条件中使用非常频繁的列。

如果只有一列被使用到,就选择单列索引,如果有多列就使用组合索引。

唯一索引

使用唯一索引不仅是为了性能,同时也为了数据的完整性。唯一索引不允许任何重复的值插入到表中。基本语法如下:

CREATE UNIQUE INDEX index_name on table_name (column_name);

局部索引

局部索引 是在表的子集上构建的索引;子集由一个条件表达式上定义。索引只包含满足条件的行。基础语法如下:

CREATE INDEX index_name on table_name (conditional_expression);

隐式索引

隐式索引 是在创建对象时,由数据库服务器自动创建的索引。索引自动创建为主键约束和唯一约束。

实例

下面实例将在 COMPANY 表的 SALARY 列上创建索引:

runoobdb=# CREATE INDEX salary_index ON COMPANY (salary);
CREATE INDEX

 现在,用 \d company 命令列出 COMPANY 表的所有索引:

runoobdb=# \d company

得到的结果如下,company_pkey 是隐式索引 ,是表创建表时创建的:

                  Table "public.company"
 Column  |     Type      | Collation | Nullable | Default 
---------+---------------+-----------+----------+---------
 id      | integer       |           | not null | 
 name    | text          |           | not null | 
 age     | integer       |           | not null | 
 address | character(50) |           |          | 
 salary  | real          |           |          | 
Indexes:
    "company_pkey" PRIMARY KEY, btree (id)
    "salary_index" btree (salary)
Triggers:
    example_trigger AFTER INSERT ON company FOR EACH ROW EXECUTE FUNCTION auditlogfunc()

你可以使用 \di 命令列出数据库中所有索引:

runoobdb=# \di
                         List of relations
 Schema |          Name           | Type  |  Owner   |    Table    
--------+-------------------------+-------+----------+-------------
 public | company1_pkey           | index | postgres | company1
 public | company2_pkey           | index | postgres | company2
 public | company_pkey            | index | postgres | company
 public | department_pkey         | index | postgres | department
 public | departments_pkey        | index | postgres | departments
 public | employee1_age_key       | index | postgres | employee1
 public | employee1_pkey          | index | postgres | employee1
 public | employee2_pkey          | index | postgres | employee2
 public | employee3_pkey          | index | postgres | employee3
 public | employee4_pkey          | index | postgres | employee4
 public | employee5_name_age_excl | index | postgres | employee5
 public | employee5_pkey          | index | postgres | employee5
 public | employee6_name_age_excl | index | postgres | employee6
 public | employee6_pkey          | index | postgres | employee6
 public | employee_pkey           | index | postgres | employee
 public | salary_index            | index | postgres | company
(16 rows)

DROP INDEX (删除索引)

一个索引可以使用 PostgreSQL 的 DROP 命令删除。

DROP INDEX index_name;

您可以使用下面的语句来删除之前创建的索引:

runoobdb=# DROP INDEX salary_index;
DROP INDEX

删除后,可以看到 salary_index 已经在索引的列表中被删除:

runoobdb=# \di
                         List of relations
 Schema |          Name           | Type  |  Owner   |    Table    
--------+-------------------------+-------+----------+-------------
 public | company1_pkey           | index | postgres | company1
 public | company2_pkey           | index | postgres | company2
 public | company_pkey            | index | postgres | company
 public | department_pkey         | index | postgres | department
 public | departments_pkey        | index | postgres | departments
 public | employee1_age_key       | index | postgres | employee1
 public | employee1_pkey          | index | postgres | employee1
 public | employee2_pkey          | index | postgres | employee2
 public | employee3_pkey          | index | postgres | employee3
 public | employee4_pkey          | index | postgres | employee4
 public | employee5_name_age_excl | index | postgres | employee5
 public | employee5_pkey          | index | postgres | employee5
 public | employee6_name_age_excl | index | postgres | employee6
 public | employee6_pkey          | index | postgres | employee6
 public | employee_pkey           | index | postgres | employee
(15 rows)

什么情况下要避免使用索引?

虽然索引的目的在于提高数据库的性能,但这里有几个情况需要避免使用索引。

使用索引时,需要考虑下列准则:

  • 索引不应该使用在较小的表上。
  • 索引不应该使用在有频繁的大批量的更新或插入操作的表上。
  • 索引不应该使用在含有大量的 NULL 值的列上。
  • 索引不应该使用在频繁操作的列上。

8,PostgreSQL ALTER TABLE 命令

在 PostgreSQL 中,ALTER TABLE 命令用于添加,修改,删除一张已经存在表的列。

另外你也可以用 ALTER TABLE 命令添加和删除约束。

语法

用 ALTER TABLE 在一张已存在的表上添加列的语法如下:

ALTER TABLE table_name ADD column_name datatype;

 在一张已存在的表上 DROP COLUMN(删除列),语法如下:

ALTER TABLE table_name DROP COLUMN column_name;

修改表中某列的 DATA TYPE(数据类型),语法如下:

ALTER TABLE table_name ALTER COLUMN column_name TYPE datatype;

给表中某列添加 NOT NULL 约束,语法如下:

ALTER TABLE table_name MODIFY column_name datatype NOT NULL;

给表中某列 ADD UNIQUE CONSTRAINT( 添加 UNIQUE 约束),语法如下:

ALTER TABLE table_name
ADD CONSTRAINT MyUniqueConstraint UNIQUE(column1, column2...);

给表中 ADD CHECK CONSTRAINT(添加 CHECK 约束),语法如下

ALTER TABLE table_name
ADD CONSTRAINT MyUniqueConstraint CHECK (CONDITION);

给表 ADD PRIMARY KEY(添加主键),语法如下:

ALTER TABLE table_name
ADD CONSTRAINT MyPrimaryKey PRIMARY KEY (column1, column2...);

DROP CONSTRAINT (删除约束),语法如下:

ALTER TABLE table_name
DROP CONSTRAINT MyUniqueConstraint;

如果是 MYSQL ,代码是这样:

ALTER TABLE table_name
DROP INDEX MyUniqueConstraint;

DROP PRIMARY KEY (删除主键),语法如下:

ALTER TABLE table_name
DROP CONSTRAINT MyPrimaryKey;

 如果是 MYSQL ,代码是这样:

ALTER TABLE table_name
DROP PRIMARY KEY;

 

实例

创建 COMPANY 表,数据内容如下:

runoobdb=# select * from company;
 id | name | age |                      address                       | salary 
----+------+-----+----------------------------------------------------+--------
  1 | Paul |  32 | California                                         |  20000
  2 | Paul |  32 | California                                         |  30000
(2 rows)

下面实例在这张表中添加新的列:

runoobdb=# ALTER TABLE COMPANY ADD GENDER char(1);
ALTER TABLE

现在表长这样:

runoobdb=# select * from company;
 id | name | age |                      address                       | salary | gender 
----+------+-----+----------------------------------------------------+--------+--------
  1 | Paul |  32 | California                                         |  20000 | 
  2 | Paul |  32 | California                                         |  30000 | 
(2 rows)

下面实例删除 GENDER 列:

runoobdb=# ALTER TABLE COMPANY DROP GENDER;
ALTER TABLE

得到结果如下:

runoobdb=# select * from company;
 id | name | age |                      address                       | salary 
----+------+-----+----------------------------------------------------+--------
  1 | Paul |  32 | California                                         |  20000
  2 | Paul |  32 | California                                         |  30000
(2 rows)

 9,PostgreSQL TRUNCATE TABLE 

PostgreSQL 中 TRUNCATE TABLE 用于删除表的数据,但不删除表结构。

也可以用 DROP TABLE 删除表,但是这个命令会连表的结构一起删除,如果想插入数据,需要重新建立这张表。

TRUNCATE TABLE 与 DELETE 具有相同的效果,但是由于它实际上并不扫描表,所以速度更快。 此外,TRUNCATE TABLE 可以立即释放表空间,而不需要后续 VACUUM 操作,这在大型表上非常有用。

PostgreSQL VACUUM 操作用于释放、再利用更新/删除行所占据的磁盘空间。

语法

TRUNCATE TABLE 基础语法如下:

TRUNCATE TABLE  table_name;

实例

创建 COMPANY 表,数据内容如下:

runoobdb=# select * from company;
 id | name | age |                      address                       | salary 
----+------+-----+----------------------------------------------------+--------
  1 | Paul |  32 | California                                         |  20000
  2 | Paul |  32 | California                                         |  30000
(2 rows)

下面实例使用了 TRUNCATE TABLE 来清除 COMPANY 表:

runoobdb=# TRUNCATE TABLE COMPANY;
TRUNCATE TABLE

得到结果如下:

runoobdb=# select * from company;
 id | name | age | address | salary 
----+------+-----+---------+--------
(0 rows)

10,PostgreSQL View(视图)

View(视图)是一张假表,只不过是通过相关的名称存储在数据库中的一个 PostgreSQL 语句。

View(视图)实际上是一个以预定义的 PostgreSQL 查询形式存在的表的组合。

View(视图)可以包含一个表的所有行或从一个或多个表选定行。

View(视图)可以从一个或多个表创建,这取决于要创建视图的 PostgreSQL 查询。

View(视图)是一种虚拟表,允许用户实现以下几点:

  • 用户或用户组认为更自然或直观查找结构数据的方式。
  • 限制数据访问,用户只能看到有限的数据,而不是完整的表。
  • 汇总各种表中的数据,用于生成报告。

PostgreSQL 视图是只读的,因此可能无法在视图上执行 DELETE、INSERT 或 UPDATE 语句。但是可以在视图上创建一个触发器,当尝试 DELETE、INSERT 或 UPDATE 视图时触发,需要做的动作在触发器内容中定义。

CREATE VIEW(创建视图)

在 PostgreSQL 用 CREATE VIEW 语句创建视图,视图创建可以从一张表,多张表或者其他视图。

CREATE VIEW 基础语法如下:

CREATE [TEMP | TEMPORARY] VIEW view_name AS
SELECT column1, column2.....
FROM table_name
WHERE [condition];

 

您可以在 SELECT 语句中包含多个表,这与在正常的 SQL SELECT 查询中的方式非常相似。如果使用了可选的 TEMP 或 TEMPORARY 关键字,则将在临时数据库中创建视图。

实例

创建 COMPANY 1表,数据内容如下:

runoobdb=# select * from company1;
 id | name  | age |                      address                       | salary | join_date  
----+-------+-----+----------------------------------------------------+--------+------------
  4 | Mark  |  25 | Rich-Mond                                          |  65000 | 2017-04-26
  5 | David |  27 | Texas                                              |  85000 | 2018-04-06
  6 | Kim   |  22 | South-Hall                                         |  45000 | 2019-09-12
(3 rows)

现在,下面是一个从 COMPANY1 表创建视图的实例。视图只从 COMPANY 表中选取几列:

runoobdb=# CREATE VIEW COMPANY_VIEW AS SELECT ID, NAME, AGE FROM  COMPANY1;
CREATE VIEW

现在,可以查询 COMPANY_VIEW,与查询实际表的方式类似。下面是实例:

runoobdb=# SELECT * FROM COMPANY_VIEW;
 id | name  | age 
----+-------+-----
  4 | Mark  |  25
  5 | David |  27
  6 | Kim   |  22
(3 rows)

DROP VIEW (删除视图)

要删除视图,只需使用带有 view_name 的 DROP VIEW 语句。DROP VIEW 的基本语法如下:

runoobdb=# DROP VIEW view_name;

下面的命令将删除我们在前面创建的 COMPANY_VIEW 视图:

runoobdb=# DROP VIEW COMPANY_VIEW;
DROP VIEW

查询结果如下:

runoobdb=# SELECT * FROM COMPANY_VIEW;
ERROR:  relation "company_view" does not exist
LINE 1: SELECT * FROM COMPANY_VIEW;

11,PostgreSQL TRANSACTION(事务)

TRANSACTION(事务)是数据库管理系统执行过程中的一个逻辑单位,由一个有限的数据库操作序列构成。

数据库事务通常包含了一个序列的对数据库的读/写操作。包含有以下两个目的:

  • 为数据库操作序列提供了一个从失败中恢复到正常状态的方法,同时提供了数据库即使在异常状态下仍能保持一致性的方法。
  • 当多个应用程序在并发访问数据库时,可以在这些应用程序之间提供一个隔离方法,以防止彼此的操作互相干扰。

当事务被提交给了数据库管理系统(DBMS),则 DBMS 需要确保该事务中的所有操作都成功完成且其结果被永久保存在数据库中,如果事务中有的操作没有成功完成,则事务中的所有操作都需要回滚,回到事务执行前的状态;同时,该事务对数据库或者其他事务的执行无影响,所有的事务都好像在独立的运行。

事务的属性

事务具有以下四个标准属性,通常根据首字母缩写为 ACID:

  • 原子性(Atomicity):事务作为一个整体被执行,包含在其中的对数据库的操作要么全部被执行,要么都不执行。
  • 一致性(Consistency):事务应确保数据库的状态从一个一致状态转变为另一个一致状态。一致状态的含义是数据库中的数据应满足完整性约束。
  • 隔离性(Isolation):多个事务并发执行时,一个事务的执行不应影响其他事务的执行。
  • 持久性(Durability):已被提交的事务对数据库的修改应该永久保存在数据库中。

例子

某人要在商店使用电子货币购买100元的东西,当中至少包括两个操作:

  • 该人账户减少 100 元。
  • 商店账户增加100元。

支持事务的数据库管理系统就是要确保以上两个操作(整个"事务")都能完成,或一起取消,否则就会出现 100 元平白消失或出现的情况。

事务控制

使用下面的命令来控制事务:

  • BEGIN TRANSACTION:开始一个事务。
  • COMMIT:事务确认,或者可以使用 END TRANSACTION 命令。
  • ROLLBACK:事务回滚。

事务控制命令只与 INSERT、UPDATE 和 DELETE 一起使用。他们不能在创建表或删除表时使用,因为这些操作在数据库中是自动提交的。

BEGIN TRANSACTION 命令

事务可以使用 BEGIN TRANSACTION 命令或简单的 BEGIN 命令来启动。此类事务通常会持续执行下去,直到遇到下一个 COMMIT 或 ROLLBACK 命令。不过在数据库关闭或发生错误时,事务处理也会回滚。以下是启动一个事务的简单语法:

COMMIT;

或者

END TRANSACTION;

ROLLBACK 命令

ROLLBACK 命令是用于撤消尚未保存到数据库的事务命令,即回滚事务。

ROLLBACK 命令的语法如下

ROLLBACK;

实例

创建 COMPANY 表,数据内容如下:

runoobdb=# select * from company2;
 id | name  | age |                      address                       | salary 
----+-------+-----+----------------------------------------------------+--------
  1 | Paul  |  32 | California                                         |  20000
  2 | Allen |  25 | Texas                                              |  15000
  3 | Teddy |  23 | Norway                                             |  20000
  4 | Mark  |  25 | Rich-Mond                                          |  65000
  5 | David |  27 | Texas                                              |  85000
  6 | Kim   |  22 | South-Hall                                         |  45000
  7 | James |  24 | Houston                                            |  10000
(7 rows)

现在,让我们开始一个事务,并从表中删除 age = 25 的记录,最后,我们使用 ROLLBACK 命令撤消所有的更改。

runoobdb=# BEGIN;
    DELETE FROM COMPANY2 WHERE AGE = 25;
    ROLLBACK;

检查 COMPANY 2表,仍然有以下记录:

runoobdb=# select * from company2;
 id | name  | age |                      address                       | salary 
----+-------+-----+----------------------------------------------------+--------
  1 | Paul  |  32 | California                                         |  20000
  2 | Allen |  25 | Texas                                              |  15000
  3 | Teddy |  23 | Norway                                             |  20000
  4 | Mark  |  25 | Rich-Mond                                          |  65000
  5 | David |  27 | Texas                                              |  85000
  6 | Kim   |  22 | South-Hall                                         |  45000
  7 | James |  24 | Houston                                            |  10000
(7 rows)

现在,让我们开始另一个事务,从表中删除 age = 25 的记录,最后我们使用 COMMIT 命令提交所有的更改。

runoobdb=# BEGIN;
    DELETE FROM COMPANY2 WHERE AGE = 25;
    COMMIT;

检查 COMPANY 2表,记录已被删除:

runoobdb=# select * from company2;
 id | name  | age |                      address                       | salary 
----+-------+-----+----------------------------------------------------+--------
  1 | Paul  |  32 | California                                         |  20000
  3 | Teddy |  23 | Norway                                             |  20000
  5 | David |  27 | Texas                                              |  85000
  6 | Kim   |  22 | South-Hall                                         |  45000
  7 | James |  24 | Houston                                            |  10000
(5 rows)

12,PostgreSQL LOCK(锁)

锁主要是为了保持数据库数据的一致性,可以阻止用户修改一行或整个表,一般用在并发较高的数据库中。

在多个用户访问数据库的时候若对并发操作不加控制就可能会读取和存储不正确的数据,破坏数据库的一致性。

数据库中有两种基本的锁:排它锁(Exclusive Locks)和共享锁(Share Locks)。

如果数据对象加上排它锁,则其他的事务不能对它读取和修改。

如果加上共享锁,则该数据库对象可以被其他事务读取,但不能修改。

LOCK 命令语法

LOCK 命令基础语法如下:

LOCK [ TABLE ]
name
 IN
lock_mode
  • name:要锁定的现有表的名称(可选模式限定)。如果只在表名之前指定,则只锁定该表。如果未指定,则锁定该表及其所有子表(如果有)。
  • lock_mode:锁定模式指定该锁与哪个锁冲突。如果没有指定锁定模式,则使用限制最大的访问独占模式。可能的值是:ACCESS SHARE,ROW SHARE, ROW EXCLUSIVE, SHARE UPDATE EXCLUSIVE, SHARE,SHARE ROW EXCLUSIVE,EXCLUSIVE,ACCESS EXCLUSIVE。

一旦获得了锁,锁将在当前事务的其余时间保持。没有解锁表命令;锁总是在事务结束时释放。

死锁

当两个事务彼此等待对方完成其操作时,可能会发生死锁。尽管 PostgreSQL 可以检测它们并以回滚结束它们,但死锁仍然很不方便。为了防止应用程序遇到这个问题,请确保将应用程序设计为以相同的顺序锁定对象。

咨询锁

PostgreSQL 提供了创建具有应用程序定义含义的锁的方法。这些被称为咨询锁。由于系统不强制使用它们,所以正确使用它们取决于应用程序。咨询锁对于不适合 MVCC 模型的锁定策略非常有用。

例如,咨询锁的一个常见用途是模拟所谓"平面文件"数据管理系统中典型的悲观锁定策略。虽然存储在表中的标志可以用于相同的目的,但是通知锁更快,避免了表膨胀,并且在会话结束时由服务器自动清理。

实例

创建 COMPANY2 表,数据内容如下:

runoobdb=# runoobdb=# select * from company2;
 id | name  | age |                      address                       | salary 
----+-------+-----+----------------------------------------------------+--------
  1 | Paul  |  32 | California                                         |  20000
  3 | Teddy |  23 | Norway                                             |  20000
  5 | David |  27 | Texas                                              |  85000
  6 | Kim   |  22 | South-Hall                                         |  45000
  7 | James |  24 | Houston                                            |  10000
(5 rows)

下面的示例将 runoobdb 数据库中的 COMPANY 2表锁定为 ACCESS EXCLUSIVE 模式。

LOCK 语句只在事务模式下工作。

runoobdb=# BEGIN;
    LOCK TABLE company1 IN ACCESS EXCLUSIVE MODE;

上面操作将得到下面结果:

LOCK TABLE

上面的消息指示表被锁定,直到事务结束,并且要完成事务,您必须回滚或提交事务。

13,PostgreSQL 子查询

子查询或称为内部查询、嵌套查询,指的是在 PostgreSQL 查询中的 WHERE 子句中嵌入查询语句。

一个 SELECT 语句的查询结果能够作为另一个语句的输入值。

子查询可以与 SELECT、INSERT、UPDATE 和 DELETE 语句一起使用,并可使用运算符如 =、<、>、>=、<=、IN、BETWEEN 等。

以下是子查询必须遵循的几个规则:

  • 子查询必须用括号括起来。

  • 子查询在 SELECT 子句中只能有一个列,除非在主查询中有多列,与子查询的所选列进行比较。

  • ORDER BY 不能用在子查询中,虽然主查询可以使用 ORDER BY。可以在子查询中使用 GROUP BY,功能与 ORDER BY 相同。

  • 子查询返回多于一行,只能与多值运算符一起使用,如 IN 运算符。

  • BETWEEN 运算符不能与子查询一起使用,但是,BETWEEN 可在子查询内使用。

SELECT 语句中的子查询使用

子查询通常与 SELECT 语句一起使用。基本语法如下:

SELECT column_name [, column_name ]
FROM   table1 [, table2 ]
WHERE  column_name OPERATOR
      (SELECT column_name [, column_name ]
      FROM table1 [, table2 ]
      [WHERE])

实例

创建 COMPANY 2表,数据内容如下:

runoobdb=# select * from company2;
 id | name  | age |                      address                       | salary 
----+-------+-----+----------------------------------------------------+--------
  1 | Paul  |  32 | California                                         |  20000
  3 | Teddy |  23 | Norway                                             |  20000
  5 | David |  27 | Texas                                              |  85000
  6 | Kim   |  22 | South-Hall                                         |  45000
  7 | James |  24 | Houston                                            |  10000
(5 rows)

现在,让我们在 SELECT 语句中使用子查询:

runoobdb=# SELECT * FROM COMPANY2 WHERE ID IN (SELECT ID FROM COMPANY2 WHERE SALARY > 45000) ;

得到结果如下:

 id | name  | age |                      address                       | salary 
----+-------+-----+----------------------------------------------------+--------
  5 | David |  27 | Texas                                              |  85000
(1 row)

INSERT 语句中的子查询使用

子查询也可以与 INSERT 语句一起使用。INSERT 语句使用子查询返回的数据插入到另一个表中。

在子查询中所选择的数据可以用任何字符、日期或数字函数修改。

基本语法如下:

INSERT INTO table_name [ (column1 [, column2 ]) ]
   SELECT [ *|column1 [, column2 ] ]
   FROM table1 [, table2 ]
   [ WHERE VALUE OPERATOR ]

实例

检查 COMPANY 2表中的内容:

runoobdb=# select * from company2;
 id | name  | age |                      address                       | salary 
----+-------+-----+----------------------------------------------------+--------
  1 | Paul  |  32 | California                                         |  20000
  3 | Teddy |  23 | Norway                                             |  20000
  5 | David |  27 | Texas                                              |  85000
  6 | Kim   |  22 | South-Hall                                         |  45000
  7 | James |  24 | Houston                                            |  10000
(5 rows)

检查 COMPANY 表中的内容:

runoobdb=# select * from company;
 id | name | age | address | salary 
----+------+-----+---------+--------
(0 rows)

假设 COMPANY 的结构与 COMPANY2 表相似,且可使用相同的 CREATE TABLE 进行创建,只是表名改为 COMPANY。现在把整个 COMPANY2 表复制到 COMPANY,语法如下:

runoobdb=# INSERT INTO COMPANY SELECT * FROM COMPANY2  WHERE ID IN (SELECT ID FROM COMPANY2) ;

再次检查 COMPANY 表中的内容:

runoobdb=# select * from company;
 id | name  | age |                      address                       | salary 
----+-------+-----+----------------------------------------------------+--------
  1 | Paul  |  32 | California                                         |  20000
  3 | Teddy |  23 | Norway                                             |  20000
  5 | David |  27 | Texas                                              |  85000
  6 | Kim   |  22 | South-Hall                                         |  45000
  7 | James |  24 | Houston                                            |  10000
(5 rows)

UPDATE 语句中的子查询使用

子查询可以与 UPDATE 语句结合使用。当通过 UPDATE 语句使用子查询时,表中单个或多个列被更新。

基本语法如下:

UPDATE table
SET column_name = new_value
[ WHERE OPERATOR [ VALUE ]
   (SELECT COLUMN_NAME
   FROM TABLE_NAME)
   [ WHERE) ]

实例

假设,我们有 COMPANY表,是 COMPANY2 表的备份。

下面的实例把 COMPANY2 表中所有 AGE 大于 27 的客户的 SALARY 更新为原来的 0.50 倍:

runoobdb=# UPDATE COMPANY2 SET SALARY = SALARY * 0.50 WHERE AGE IN (SELECT AGE FROM COMPANY WHERE AGE >= 27 );
UPDATE 2

这将影响两行,最后 COMPANY 2表中的记录如下:

runoobdb=# select * from company2;
 id | name  | age |                      address                       | salary 
----+-------+-----+----------------------------------------------------+--------
  3 | Teddy |  23 | Norway                                             |  20000
  6 | Kim   |  22 | South-Hall                                         |  45000
  7 | James |  24 | Houston                                            |  10000
  1 | Paul  |  32 | California                                         |  10000
  5 | David |  27 | Texas                                              |  42500
(5 rows)

DELETE 语句中的子查询使用

子查询可以与 DELETE 语句结合使用,就像上面提到的其他语句一样。

基本语法如下:

DELETE FROM TABLE_NAME
[ WHERE OPERATOR [ VALUE ]
   (SELECT COLUMN_NAME
   FROM TABLE_NAME)
   [ WHERE) ]

实例

假设,我们有 COMPANY 表,是 COMPANY2 表的备份。

下面的实例删除 COMPANY 2表中所有 AGE 大于或等于 27 的客户记录:

runoobdb=# DELETE FROM COMPANY2 WHERE AGE IN (SELECT AGE FROM COMPANY WHERE AGE > 27 );

这将影响一行,最后 COMPANY 表中的记录如下:

runoobdb=# select * from company2;
 id | name  | age |                      address                       | salary 
----+-------+-----+----------------------------------------------------+--------
  3 | Teddy |  23 | Norway                                             |  20000
  6 | Kim   |  22 | South-Hall                                         |  45000
  7 | James |  24 | Houston                                            |  10000
  5 | David |  27 | Texas                                              |  42500
(4 rows)

14,PostgreSQL AUTO INCREMENT(自动增长)

AUTO INCREMENT(自动增长) 会在新记录插入表中时生成一个唯一的数字。

PostgreSQL 使用序列来标识字段的自增长,数据类型有 smallserial、serial 和 bigserial 。这些属性类似于 MySQL 数据库支持的 AUTO_INCREMENT 属性。

使用 MySQL 设置自动增长的语句如下:

CREATE TABLE IF NOT EXISTS `runoob_tbl`(
   `runoob_id` INT UNSIGNED AUTO_INCREMENT,
   `runoob_title` VARCHAR(100) NOT NULL,
   `runoob_author` VARCHAR(40) NOT NULL,
   `submission_date` DATE,
   PRIMARY KEY ( `runoob_id` )
)ENGINE=InnoDB DEFAULT CHARSET=utf8;

MySQL 是用 AUTO_INCREMENT 这个属性来标识字段的自增。

PostgreSQL 使用序列来标识字段的自增长:

CREATE TABLE runoob
(
    id serial NOT NULL,
    alttext text,
    imgurl text
)

SMALLSERIAL、SERIAL 和 BIGSERIAL 范围:

伪类型 存储大小 范围
SMALLSERIAL 2字节 1 到 32,767
SERIAL 4字节 1 到 2,147,483,647
BIGSERIAL 8字节 1 到 922,337,2036,854,775,807

语法

SERIAL 数据类型基础语法如下:

CREATE TABLE tablename (
   colname SERIAL
);

实例

假定我们要创建一张 COMPANY3 表,并创建下面几个字段:

runoobdb=# CREATE TABLE COMPANY3(
   ID  SERIAL PRIMARY KEY,
   NAME           TEXT      NOT NULL,
   AGE            INT       NOT NULL,
   ADDRESS        CHAR(50),
   SALARY         REAL
);

检查 COMPANY 3表中的内容:

runoobdb=# select * from company3;
 id | name | age | address | salary 
----+------+-----+---------+--------
(0 rows)

现在往表中插入几条记录:

INSERT INTO COMPANY3 (NAME,AGE,ADDRESS,SALARY)
VALUES ( 'Paul', 32, 'California', 20000.00 );

INSERT INTO COMPANY3 (NAME,AGE,ADDRESS,SALARY)
VALUES ('Allen', 25, 'Texas', 15000.00 );

INSERT INTO COMPANY3 (NAME,AGE,ADDRESS,SALARY)
VALUES ('Teddy', 23, 'Norway', 20000.00 );

INSERT INTO COMPANY3 (NAME,AGE,ADDRESS,SALARY)
VALUES ( 'Mark', 25, 'Rich-Mond ', 65000.00 );

INSERT INTO COMPANY3 (NAME,AGE,ADDRESS,SALARY)
VALUES ( 'David', 27, 'Texas', 85000.00 );

INSERT INTO COMPANY3 (NAME,AGE,ADDRESS,SALARY)
VALUES ( 'Kim', 22, 'South-Hall', 45000.00 );

INSERT INTO COMPANY3 (NAME,AGE,ADDRESS,SALARY)
VALUES ( 'James', 24, 'Houston', 10000.00 );

再次检查 COMPANY 3表中的内容:

runoobdb=# select * from company3;                                               id | name  | age |                      address                       | salary 
----+-------+-----+----------------------------------------------------+--------
  1 | Paul  |  32 | California                                         |  20000
  2 | Allen |  25 | Texas                                              |  15000
  3 | Teddy |  23 | Norway                                             |  20000
  4 | Mark  |  25 | Rich-Mond                                          |  65000
  5 | David |  27 | Texas                                              |  85000
  6 | Kim   |  22 | South-Hall                                         |  45000
  7 | James |  24 | Houston                                            |  10000
(7 rows)

15,PostgreSQL PRIVILEGES(权限)

无论何时创建数据库对象,都会为其分配一个所有者,所有者通常是执行 create 语句的人。

对于大多数类型的对象,初始状态是只有所有者(或超级用户)才能修改或删除对象。要允许其他角色或用户使用它,必须为该用户设置权限。

在 PostgreSQL 中,权限分为以下几种:

  • SELECT
  • INSERT
  • UPDATE
  • DELETE
  • TRUNCATE
  • REFERENCES
  • TRIGGER
  • CREATE
  • CONNECT
  • TEMPORARY
  • EXECUTE
  • USAGE

根据对象的类型(表、函数等),将指定权限应用于该对象。

要向用户分配权限,可以使用 GRANT 命令。

GRANT 语法

GRANT 命令的基本语法如下:

GRANT privilege [, ...]
ON object [, ...]
TO { PUBLIC | GROUP group | username }
  • privilege − 值可以为:SELECT,INSERT,UPDATE,DELETE, RULE,ALL。
  • object − 要授予访问权限的对象名称。可能的对象有: table, view,sequence。
  • PUBLIC − 表示所有用户。
  • GROUP group − 为用户组授予权限。
  • username − 要授予权限的用户名。PUBLIC 是代表所有用户的简短形式。

另外,我们可以使用 REVOKE 命令取消权限,REVOKE 语法:

REVOKE privilege [, ...]
ON object [, ...]
FROM { PUBLIC | GROUP groupname | username }

实例

为了理解权限,创建一个用户:

runoobdb=# CREATE USER runoob WITH PASSWORD 'password';
CREATE ROLE

信息 CREATE ROLE 表示创建了一个用户 "runoob"。

实例

创建 COMPANY3 表,数据内容如下:

runoobdb=# select * from company3;
 id | name  | age |                      address                       | salary 
----+-------+-----+----------------------------------------------------+--------
  1 | Paul  |  32 | California                                         |  20000
  2 | Allen |  25 | Texas                                              |  15000
  3 | Teddy |  23 | Norway                                             |  20000
  4 | Mark  |  25 | Rich-Mond                                          |  65000
  5 | David |  27 | Texas                                              |  85000
  6 | Kim   |  22 | South-Hall                                         |  45000
  7 | James |  24 | Houston                                            |  10000
(7 rows)

现在给用户 "runoob" 分配权限:

runoobdb=# GRANT ALL ON COMPANY3 TO runoob;
GRANT

信息 GRANT 表示所有权限已经分配给了 "runoob"。

下面撤销用户 "runoob" 的权限:

runoobdb=# REVOKE ALL ON COMPANY FROM runoob;
REVOKE

信息 REVOKE 表示已经将用户的权限撤销。

你也可以删除用户:

runoobdb=# DROP USER runoob;
DROP ROLE

信息 DROP ROLE 表示用户 "runoob" 已经从数据库中删除。

16,PostgreSQL 时间/日期函数和操作符

日期/时间操做符

下表演示了基本算术操作符的行为(+,*, 等):

操作符 例子 结果
+ date '2001-09-28' + integer '7' date '2001-10-05'
+ date '2001-09-28' + interval '1 hour' timestamp '2001-09-28 01:00:00'
+ date '2001-09-28' + time '03:00' timestamp '2001-09-28 03:00:00'
+ interval '1 day' + interval '1 hour' interval '1 day 01:00:00'
+ timestamp '2001-09-28 01:00' + interval '23 hours' timestamp '2001-09-29 00:00:00'
+ time '01:00' + interval '3 hours' time '04:00:00'
- - interval '23 hours' interval '-23:00:00'
- date '2001-10-01' - date '2001-09-28' integer '3' (days)
- date '2001-10-01' - integer '7' date '2001-09-24'
- date '2001-09-28' - interval '1 hour' timestamp '2001-09-27 23:00:00'
- time '05:00' - time '03:00' interval '02:00:00'
- time '05:00' - interval '2 hours' time '03:00:00'
- timestamp '2001-09-28 23:00' - interval '23 hours' timestamp '2001-09-28 00:00:00'
- interval '1 day' - interval '1 hour' interval '1 day -01:00:00'
- timestamp '2001-09-29 03:00' - timestamp '2001-09-27 12:00' interval '1 day 15:00:00'
* 900 * interval '1 second' interval '00:15:00'
* 21 * interval '1 day' interval '21 days'
* double precision '3.5' * interval '1 hour' interval '03:30:00'
/ interval '1 hour' / double precision '1.5' interval '00:40:00'

日期/时间函数

函数 返回类型 描述 例子 结果
age(timestamp, timestamp) interval 减去参数后的"符号化"结果,使用年和月,不只是使用天 age(timestamp '2001-04-10', timestamp '1957-06-13') 43 years 9 mons 27 days
age(timestamp) interval current_date减去参数后的结果(在午夜) age(timestamp '1957-06-13') 43 years 8 mons 3 days
clock_timestamp() timestamp with time zone 实时时钟的当前时间戳(在语句执行时变化)    
current_date date 当前的日期;    
current_time time with time zone 当日时间;    
current_timestamp timestamp with time zone 当前事务开始时的时间戳;    
date_part(text, timestamp) double precision 获取子域(等效于extract); date_part('hour', timestamp '2001-02-16 20:38:40') 20
date_part(text, interval) double precision 获取子域(等效于extract); date_part('month', interval '2 years 3 months') 3
date_trunc(text, timestamp) timestamp 截断成指定的精度; date_trunc('hour', timestamp '2001-02-16 20:38:40') 2001-02-16 20:00:00
date_trunc(text, interval) interval 截取指定的精度, date_trunc('hour', interval '2 days 3 hours 40 minutes') 2 days 03:00:00
extract(field from timestamp) double precision 获取子域; extract(hour from timestamp '2001-02-16 20:38:40') 20
extract(field from interval) double precision 获取子域; extract(month from interval '2 years 3 months') 3
isfinite(date) boolean 测试是否为有穷日期(不是 +/-无穷) isfinite(date '2001-02-16') true
isfinite(timestamp) boolean 测试是否为有穷时间戳(不是 +/-无穷) isfinite(timestamp '2001-02-16 21:28:30') true
isfinite(interval) boolean 测试是否为有穷时间间隔 isfinite(interval '4 hours') true
justify_days(interval) interval 按照每月 30 天调整时间间隔 justify_days(interval '35 days') 1 mon 5 days
justify_hours(interval) interval 按照每天 24 小时调整时间间隔 justify_hours(interval '27 hours') 1 day 03:00:00
justify_interval(interval) interval 使用justify_daysjustify_hours调整时间间隔的同时进行正负号调整 justify_interval(interval '1 mon -1 hour') 29 days 23:00:00
localtime time 当日时间;    
localtimestamp timestamp 当前事务开始时的时间戳;    
make_date(year int, month int, day int) date 为年、月和日字段创建日期 make_date(2013, 7, 15) 2013-07-15
make_interval(years int DEFAULT 0, months int DEFAULT 0, weeks int DEFAULT 0, days int DEFAULT 0, hours int DEFAULT 0, mins int DEFAULT 0, secs double precision DEFAULT 0.0) interval 从年、月、周、天、小时、分钟和秒字段中创建间隔 make_interval(days := 10) 10 days
make_time(hour int, min int, sec double precision) time 从小时、分钟和秒字段中创建时间 make_time(8, 15, 23.5) 08:15:23.5
make_timestamp(year int, month int, day int, hour int, min int, sec double precision) timestamp 从年、月、日、小时、分钟和秒字段中创建时间戳 make_timestamp(2013, 7, 15, 8, 15, 23.5) 2013-07-15 08:15:23.5
make_timestamptz(year int, month int, day int, hour int, min int, sec double precision, [ timezone text ]) timestamp with time zone 从年、月、日、小时、分钟和秒字段中创建带有时区的时间戳。 没有指定timezone时,使用当前的时区。 make_timestamptz(2013, 7, 15, 8, 15, 23.5) 2013-07-15 08:15:23.5+01
now() timestamp with time zone 当前事务开始时的时间戳;    
statement_timestamp() timestamp with time zone 实时时钟的当前时间戳;    
timeofday() text clock_timestamp相同,但结果是一个text 字符串;    
transaction_timestamp() timestamp with time zone 当前事务开始时的时间戳;    

18,PostgreSQL 常用函数

PostgreSQL 内置函数也称为聚合函数,用于对字符串或数字数据执行处理。

下面是所有通用 PostgreSQL 内置函数的列表:

  • COUNT 函数:用于计算数据库表中的行数。
  • MAX 函数:用于查询某一特定列中最大值。
  • MIN 函数:用于查询某一特定列中最小值。
  • AVG 函数:用于计算某一特定列中平均值。
  • SUM 函数:用于计算数字列所有值的总和。
  • ARRAY 函数:用于输入值(包括null)添加到数组中。
  • Numeric 函数:完整列出一个 SQL 中所需的操作数的函数。
  • String 函数:完整列出一个 SQL 中所需的操作字符的函数。

数学函数

下面是PostgreSQL中提供的数学函数列表,需要说明的是,这些函数中有许多都存在多种形式,区别只是参数类型不同。除非特别指明,任何特定形式的函数都返回和它的参数相同的数据类型。

函数 返回类型 描述 例子 结果
abs(x)   绝对值 abs(-17.4) 17.4
cbrt(double)   立方根 cbrt(27.0) 3
ceil(double/numeric)   不小于参数的最小的整数 ceil(-42.8) -42
degrees(double)   把弧度转为角度 degrees(0.5) 28.6478897565412
exp(double/numeric)   自然指数 exp(1.0) 2.71828182845905
floor(double/numeric)   不大于参数的最大整数 floor(-42.8) -43
ln(double/numeric)   自然对数 ln(2.0) 0.693147180559945
log(double/numeric)   10为底的对数 log(100.0) 2
log(b numeric,x numeric) numeric 指定底数的对数 log(2.0, 64.0) 6.0000000000
mod(y, x)   取余数 mod(9,4) 1
pi() double "π"常量 pi() 3.14159265358979
power(a double, b double) double 求a的b次幂 power(9.0, 3.0) 729
power(a numeric, b numeric) numeric 求a的b次幂 power(9.0, 3.0) 729
radians(double) double 把角度转为弧度 radians(45.0) 0.785398163397448
random() double 0.0到1.0之间的随机数值 random()  
round(double/numeric)   圆整为最接近的整数 round(42.4) 42
round(v numeric, s int) numeric 圆整为s位小数数字 round(42.438,2) 42.44
sign(double/numeric)   参数的符号(-1,0,+1) sign(-8.4) -1
sqrt(double/numeric)   平方根 sqrt(2.0) 1.4142135623731
trunc(double/numeric)   截断(向零靠近) trunc(42.8) 42
trunc(v numeric, s int) numeric 截断为s小数位置的数字 trunc(42.438,2) 42.43

三角函数列表

函数 描述
acos(x) 反余弦
asin(x) 反正弦
atan(x) 反正切
atan2(x, y) 正切 y/x 的反函数
cos(x) 余弦
cot(x) 余切
sin(x) 正弦
tan(x) 正切

字符串函数和操作符

下面是 PostgreSQL 中提供的字符串操作符列表:

函数 返回类型 描述 例子 结果
string 丨丨 string text 字串连接 'Post' 丨丨 'greSQL' PostgreSQL
bit_length(string) int 字串里二进制位的个数 bit_length('jose') 32
char_length(string) int 字串中的字符个数 char_length('jose') 4
convert(string using conversion_name) text 使用指定的转换名字改变编码。 convert('PostgreSQL' using iso_8859_1_to_utf8) 'PostgreSQL'
lower(string) text 把字串转化为小写 lower('TOM') tom
octet_length(string) int 字串中的字节数 octet_length('jose') 4
overlay(string placing string from int [for int]) text 替换子字串 overlay('Txxxxas' placing 'hom' from 2 for 4) Thomas
position(substring in string) int 指定的子字串的位置 position('om' in 'Thomas') 3
substring(string [from int] [for int]) text 抽取子字串 substring('Thomas' from 2 for 3) hom
substring(string from pattern) text 抽取匹配 POSIX 正则表达式的子字串 substring('Thomas' from '…$') mas
substring(string from pattern for escape) text 抽取匹配SQL正则表达式的子字串 substring('Thomas' from '%#"o_a#"_' for '#') oma
trim([leading丨trailing 丨 both] [characters] from string) text 从字串string的开头/结尾/两边/ 删除只包含characters(默认是一个空白)的最长的字串 trim(both 'x' from 'xTomxx') Tom
upper(string) text 把字串转化为大写。 upper('tom') TOM
ascii(text) int 参数第一个字符的ASCII码 ascii('x') 120
btrim(string text [, characters text]) text 从string开头和结尾删除只包含在characters里(默认是空白)的字符的最长字串 btrim('xyxtrimyyx','xy') trim
chr(int) text 给出ASCII码的字符 chr(65) A
convert(string text, [src_encoding name,] dest_encoding name) text 把字串转换为dest_encoding convert( 'text_in_utf8', 'UTF8', 'LATIN1') 以ISO 8859-1编码表示的text_in_utf8
initcap(text) text 把每个单词的第一个子母转为大写,其它的保留小写。单词是一系列字母数字组成的字符,用非字母数字分隔。 initcap('hi thomas') Hi Thomas
length(string text) int string中字符的数目 length('jose') 4
lpad(string text, length int [, fill text]) text 通过填充字符fill(默认为空白),把string填充为长度length。 如果string已经比length长则将其截断(在右边)。 lpad('hi', 5, 'xy') xyxhi
ltrim(string text [, characters text]) text 从字串string的开头删除只包含characters(默认是一个空白)的最长的字串。 ltrim('zzzytrim','xyz') trim
md5(string text) text 计算给出string的MD5散列,以十六进制返回结果。 md5('abc')  
repeat(string text, number int) text 重复string number次。 repeat('Pg', 4) PgPgPgPg
replace(string text, from text, to text) text 把字串string里出现地所有子字串from替换成子字串to。 replace('abcdefabcdef', 'cd', 'XX') abXXefabXXef
rpad(string text, length int [, fill text]) text 通过填充字符fill(默认为空白),把string填充为长度length。如果string已经比length长则将其截断。 rpad('hi', 5, 'xy') hixyx
rtrim(string text [, character text]) text 从字串string的结尾删除只包含character(默认是个空白)的最长的字 rtrim('trimxxxx','x') trim
split_part(string text, delimiter text, field int) text 根据delimiter分隔string返回生成的第field个子字串(1 Base)。 split_part('abc~@~def~@~ghi', '~@~', 2) def
strpos(string, substring) text 声明的子字串的位置。 strpos('high','ig') 2
substr(string, from [, count]) text 抽取子字串。 substr('alphabet', 3, 2) ph
to_ascii(text [, encoding]) text 把text从其它编码转换为ASCII。 to_ascii('Karel') Karel
to_hex(number int/bigint) text 把number转换成其对应地十六进制表现形式。 to_hex(9223372036854775807) 7fffffffffffffff
translate(string text, from text, to text) text 把在string中包含的任何匹配from中的字符的字符转化为对应的在to中的字符。 translate('12345', '14', 'ax') a23x5

类型转换相关函数

函数 返回类型 描述 实例
to_char(timestamp, text) text 将时间戳转换为字符串 to_char(current_timestamp, 'HH12:MI:SS')
to_char(interval, text) text 将时间间隔转换为字符串 to_char(interval '15h 2m 12s', 'HH24:MI:SS')
to_char(int, text) text 整型转换为字符串 to_char(125, '999')
to_char(double precision, text) text 双精度转换为字符串 to_char(125.8::real, '999D9')
to_char(numeric, text) text 数字转换为字符串 to_char(-125.8, '999D99S')
to_date(text, text) date 字符串转换为日期 to_date('05 Dec 2000', 'DD Mon YYYY')
to_number(text, text) numeric 转换字符串为数字 to_number('12,454.8-', '99G999D9S')
to_timestamp(text, text) timestamp 转换为指定的时间格式 time zone convert string to time stamp to_timestamp('05 Dec 2000', 'DD Mon YYYY')
to_timestamp(double precision) timestamp 把UNIX纪元转换成时间戳 to_timestamp(1284352323)

你可能感兴趣的:(SQL)