PostgreSQL的50个案例,你想要的全都有

文章目录

    • 本篇要点
    • 什么是SQL
    • 什么是ANSI SQL标准?
    • 兼容性
    • 50个例子
      • 1. create table创建表
      • 2. insert插入数据
      • 3. select查询,没有where子句
      • 4. udpate更新数据
      • 5. delete删除数据
      • 6. 比较符的运用
        • 小于等于
        • 大于等于
        • 不等于
        • 等于
      • 7.select distinct去重查询
        • 没有去重之前
        • 去重之后
      • 8. truncate清空表
      • 9. drop 删除表
      • 10. create view 创建视图
      • 11. 使用select语句创建表
      • 12. 设定超时
      • 13. 使用create sequence
      • 14. 导入blob数据类型
      • 15. ilike不区分大小写
        • 在where中使用ilike查询
      • 16. 层次化查询
      • 17. 计算长度的函数
        • 主查询
        • 使用长度函数
      • 18. 发生has no destination for result data
        • 使用PERFORM
        • 在select into语句中使用变量
      • 19. 导出结果集
        • 导出结果集到text文件
        • 从text文件导入数据
      • 20. 展示所有的数据库
      • 21. 检查语句执行时间
      • 22. 动态sql语句
      • 23. count计数
      • 24. 分页 limit 和 offset
      • 25. IF … ELSE 表达式
      • 26. 使用join更新
      • 27. inner join
      • 28. case表达式
      • 29. 递归查询
      • 30. log查询
      • 31. 使用变量
        • 在where条件中使用变量
      • 32. 日期查询
      • 33. return query
      • 34. 并行查询
      • 35. 逻辑运算符
      • 36. 捕获重复的行
      • 37. 枚举
      • 38. pivot table
      • 39. self join自连接
      • 40. 父子递归
      • 41. 定义变量
      • 42. prepare语句
      • 43. 检查null值
      • 44. 使用exists检查查询是否为空
      • 45. 语句执行时间日志
      • 46. 在shell脚本中执行查询
      • 47. union操作符
      • 48. 查询优化的命令
        • explain
        • vacuum
        • analyze
        • Database indexes
        • PostgreSQL configuration parameters
      • 49. alter table添加或修改列
      • 50. comment注释

翻译自原文链接: PostgreSQL Query: Introduction, Explanation, and 50 Examples

本篇要点

  • 介绍一个SQL查询是怎么样的。
  • 如何在PostgreSQL中使用SQL查询。

我将提供50个SQL查询的例子,一起来学习吧。

什么是SQL

SQL是结构化查询语言Structured Query Language的缩写。 最初,它被称为SEQUEL(结构化英语查询语言),用于存储和处理数据库中的数据。 如今,SQL被广泛用于在关系数据库管理系统(RDBMS)中执行所有类型的数据操作。

SQL是一种功能强大的语言,我们可以在其中执行各种操作,如:

  • 执行查询
  • 获取数据
  • 在数据库中插入,更新和删除记录(DML操作)
  • 在数据库中创建新对象(DDL操作)
  • 在表,过程,函数和视图上设置权限
  • 还有更多…

什么是ANSI SQL标准?

美国国家标准协会(ANSI)于1986年创建了SQL标准,并于1987年被国际标准化组织(ISO)采纳。要使每个RDBMS都符合ANSI标准,它们都必须用尽可能相似的命令支持一些主要的命令,例如DML。

SQL遵循ANSI / ISO标准,但是不同的数据库系统使用不同版本的SQL语言。例如,在PostgreSQL中,我们可以使用RETURNING子句执行INSERT操作,而并非所有其他数据库都能做到。

即使如此,不同的数据库系统需要符合ANSI标准,所有数据库都以相同的方式支持命令(如DELETE,UPDATE,SELECT,INSERT),也就是说,语法应在任何地方都可以使用。

兼容性

INSERT为例,它符合SQL的标准,不同之处在于RETURNING子句是PostgreSQL扩展,类似的还有:

  • 在INSERT中使用WITH的能力。
  • 以及在ON CONFLICT中指定替代动作的能力。
  • 此外,标准不允许列名列表被省略,但PostgreSQL中不是所有的列都由VALUES子句或查询填充的情况。

SQL标准指定:只有id列存在的时候,OVERRIDING SYSTEM VALUE才可以被指定,但 PostgreSQL在任何情况下都允许该子句,如果不适用则将其忽略。

如果你想知道更多具体清晰的区别,可以查看PostgreSQL的文档。

50个例子

现在让我们学习探索一些常见实用的PostgreSQL的demo吧。

1. create table创建表

创建一个空表,由命令发起人拥有。

      postgres=# create table dummy_table(name varchar(20),address text,age int);
      CREATE TABLE

2. insert插入数据

向表中插入数据

        postgres=# insert into dummy_table values('XYZ','location-A',25);
        INSERT 0 1
        postgres=# insert into dummy_table values('ABC','location-B',35);
        INSERT 0 1
        postgres=# insert into dummy_table values('DEF','location-C',40);
        INSERT 0 1
        postgres=# insert into dummy_table values('PQR','location-D',54);
        INSERT 0 1

3. select查询,没有where子句

没有指定where条件,将会从数据库中获取所有的记录

        postgres=# select * from dummy_table;
        name |  address   | age 
        ---------+--------------+ -----
        XYZ   | location-A |  25
        ABC   | location-B |  35
        DEF   | location-C |  40
        PQR   | location-D |  54
        (4 rows)

4. udpate更新数据

PQR的年龄更新为50

        postgres=# update dummy_table set age=50 where name='PQR';
        UPDATE 1
        postgres=# select * from dummy_table;
        name |  address   | age 
        --------+--------------+-------
        XYZ  | location-A |  25
        ABC  | location-B |  35
        DEF  | location-C |  40
        PQR  | location-D |  50
        (4 rows)

为地址为location-D的人设置姓名和年龄

postgres=# update dummy_table set name='GHI',age=54 where address='location-D';
UPDATE 1
postgres=# select * from dummy_table;
 name |  address   | age 
------+------------+-----
 XYZ  | location-A |  25
 ABC  | location-B |  35
 DEF  | location-C |  40
 GHI  | location-D |  54
(4 rows)

postgres=# 

如果我们要更新所有记录的address和age,我们不需要使用where子句。

postgres=# update dummy_table set age=54,address='location-X';
UPDATE 4


postgres=# select * from dummy_table ;
 name |  address   | age 
------+------------+--------
 XYZ  | location-X |  54
 ABC  | location-X |  54
 DEF  | location-X |  54
 GHI  | location-X |  54
(4 rows)

postgres=# 

另外,可以使用RETURNING子句返回更新后的字段,建议在事务中执行该操作:BEGIN...COMMIT/ROLLBACK

postgres=# update dummy_table set age=30 where name='XYZ' returning age as age_no;
 age_no 
---------
      30
(1 row)

UPDATE 1

5. delete删除数据

删除行,可以指定where也可没有,如果缺少where条件,将会删除所有行,并保留一个空表,以下示例删除年龄为65的行。

postgres=# delete from dummy_table where age=65;
DELETE 1
postgres=# 

6. 比较符的运用

可以解决比较符号找到满足指定条件或值的列。

小于等于

postgres=# select * from dummy_table where age <=50;
 name |  address   | age 
------+------------+-----
 XYZ  | location-A |  25
 ABC  | location-B |  35
 DEF  | location-C |  40
 PQR  | location-D |  50
(4 rows)

大于等于

postgres=# select * from dummy_table where age>=50;
 name |  address   | age 
------+------------+-----
 PQR  | location-D |  50
(1 row)

不等于

postgres=# select * from dummy_table where age<>50;
 name |  address   | age 
------+------------+-----
 XYZ  | location-A |  25
 ABC  | location-B |  35
 DEF  | location-C |  40
(3 rows)

等于

postgres=# select * from dummy_table where age=50;
 name |  address   | age 
------+------------+-----
 PQR  | location-D |  50
(1 row)

7.select distinct去重查询

返回不重复的值。

没有去重之前

postgres=# select age from dummy_table order by 1;
 age 
-----
   1
   1
   2
   2
   3
(5 rows)

去重之后

postgres=# select distinct age from dummy_table order by 1;
 age 
-----
   1
   2
   3
(3 rows)

8. truncate清空表

清空一个表

postgres=# truncate table dummy_table;
TRUNCATE TABLE

9. drop 删除表

从数据库中移除这个表,包括该表的所有关联数据,索引,规则,触发器和约束。

postgresql=# drop table if exists dummy;
NOTICE:  table "dummy" does not exist, skipping
DROP TABLE

10. create view 创建视图

生成视图【伪表】,从表、子集或从基础表中选择的列形成的虚拟表。

postgres=# create or replace view vi as select * from dummy_table where age is NULL;
CREATE VIEW

11. 使用select语句创建表

postgres=# select 'My name  is X' as col1 , 10 as col2, 'Address is -XYZ location' as col3  into new_table;
SELECT 1
postgres=# select * from new_table ;
     col1      | col2 |           col3           
---------------+------+--------------------------
 My name  is X |   10 | Address is -XYZ location
(1 row)

12. 设定超时

在GUC参数的帮助下,我们可以指定某个查询在特定的时间段后超时,中止,精确到毫秒。

postgresql=# set statement_timeout=10;
SET
postgresql=# select pg_sleep(20);
ERROR:  canceling statement due to statement timeout

13. 使用create sequence

该命令为序列号生成器,创建序列后,我们可以使用序列的nextval和currval函数将值插入表中。

postgres=# create sequence seq;
CREATE SEQUENCE
postgres=# create table tab(n int);
CREATE TABLE
postgres=# insert into tab values (nextval('seq'));
INSERT 0 1
postgres=# insert into tab values (currval('seq'));
INSERT 0 1
postgres=# insert into tab values (nextval('seq'));
INSERT 0 1
postgres=# select * from tab;
 n 
---
 1
 1
 2
(3 rows)

14. 导入blob数据类型

PostgreSQL不直接支持BLOB(二进制大对象),但是我们可以使用以下方法使用:

假设你在/home/edb文件夹中下载了PNG格式的图像。

[edb@localhost]$ ls /home/edb/mypic.png 
/home/edb/mypic.png

如果你想将他存到postgreSQL中,进入postgreSQL安装的bin目录下,链接psql终端:

postgres=# Create table testing(n int,n1 oid);
CREATE TABLE
postgres=# insert into testing values (1,lo_import('/home/edb/mypic.png'));
INSERT 0 1

lo_import()函数将命名文件加载到pg_largeobject中,并返回一个将引用大对象的OID【Object identifier】值。选择表仅显示OID,而不显示组成这张照片的bits。

15. ilike不区分大小写

ILIKE运算符是与LIKE运算符相似的匹配函数,但具有不区分大小写的有点。

postgres=# select * from ted;
  n  
-----
 TAR
 TaR
 Tar
 tar
(4 rows)

在where中使用ilike查询

postgres=# select * from ted where n ilike 'TAR%';
  n  
-----
 TAR
 TaR
 Tar
 tar
(4 rows)

16. 层次化查询

层次查询是指结果具有结构化或父子关系并以树结构显示的查询。 若要查看分层查询的工作方式,需要创建一个虚拟表。

create table test_table(  
  emp_no                int,  
  ename                 char(5),  
  job                       char(9),  
  manager_no        int
);

向表中插入一些数据

insert into test_table values(10,'A1','CEO',null);
insert into test_table values(11, 'B1', 'VP', 10);
insert into test_table values(12, 'B2', 'VP', 10);
insert into test_table values(13, 'B3', 'VP', 10);
insert into test_table values(14, 'C1', 'DIRECTOR', 13);
insert into test_table values(15, ‘C2’, ‘DIRECTOR’, 13);
insert into test_table values(16, 'D1', 'MANAGER', 15);
insert into test_table values(17 ,'E1', 'ENGINEER', 11);
insert into test_table values(18, 'E2', 'ENGINEER', 11);

创建完成之后,就可以按照下面的方法去层次化查询了。

17. 计算长度的函数

返回指定字符串变量中的字符数或字节数。

主查询

postgres=# select name,age from dummy_table;
 name | age 
------+-----
 XYZ  |  25
 ABC  |  35
 DEF  |  40
 PQR  |  54
 PQR  |    
(5 rows)

使用长度函数

postgres=# select length(name),length(age) from dummy_table;
 length | length 
--------+--------
      3 |      2
      3 |      2
      3 |      2
      3 |      2
      3 |       
(5 rows)

18. 发生has no destination for result data

如果我们收到了query has no destination for result data的异常消息,我们可以使用以下方法去避免。

使用PERFORM

postgres=# create or replace function f(n int) 
returns int 
as 
$$ 
begin 
perform
now(); 
 return 1; 
 end; 
$$ language 'plpgsql';
CREATE FUNCTION
postgresql=# select f(9);
 f 
---
 1
(1 row)

在select into语句中使用变量

postgres=# create or replace function f(n int) 
returns int 
as 
$$ 
declare 
a date;
begin 
select now() into a;
raise notice ‘%s’,a; 
return 1; 
end; 
$$ language 'plpgsql';
CREATE FUNCTION
 
 
postgresql=# select f(9);
          NOTICE: 24-SEP-20 13:15:46.23388s
             f
            ---
            1
        (1 row)

19. 导出结果集

借助COPY命令,我们可以将数据从表导出到外部文本文件,也可以将数据从文本文件导入到表中。

导出结果集到text文件

postgres=#  copy dummy_table to '/tmp/abc.txt';
COPY 5
  
postgres=# \! cat /tmp/abc.txt
XYZ	location-A	25
ABC	location-B	35
DEF	location-C	40
PQR	location-D	50
CXC	1	50

从text文件导入数据

postgres=# copy dummy_table from '/tmp/abc.txt';
COPY 5

20. 展示所有的数据库

postgres=# select oid,datname from pg_database;
  oid     |  datname  
-----------+-----------
 13743 | postgres
     1     | template1
 13742 | template0
(3 rows) 

我们还可以在psql prompt下使用\l命令列出所有的数据库名。

21. 检查语句执行时间

psql promt下使用\timing指令开启。

postgres=# \timing
Timing is on.

现在查询之后就会显示执行时间了。

postgres=# select * from dummy_table;
 name |  address   | age 
------+------------+--------
 XYZ  | location-A | 25
 ABC  | location-B | 35
 DEF  | location-C | 40
 PQR  | location-D | 50
 CXC  | 1               | 50
(5 rows)
 
Time: 0.440 ms
postgres=# 

22. 动态sql语句

  • 在查询中,动态SQL用于减少重复性任务。
  • 动态SQL查询不会缓存在内存中。
postgres=# do
postgres-# $$
postgres$# begin
postgres$# execute 'select * from dummy_table';
postgres$# end;
postgres$# $$;
DO

23. count计数

返回表中的行数,如果使用count(*)将包含null值,否则将排除。

postgres=# select count(*) from dummy_table;
 count 
-------
     5
(1 row)
 
postgres=# select count(avg) from dummy_table;
 count 
-------
     4
(1 row)

24. 分页 limit 和 offset

limit限制返回的记录数。

postgres=# select * from dummy_table  limit 1;
 name |  address   | age 
------+------------+-----
 XYZ  | location-A |  25
(1 row)

offset用于跳过我们不需要的数据。

postgres=# select * from dummy_table  offset 4;
 name | address | age 
------+---------+-----
 cxc  | 1       |  50
(1 row)

25. IF … ELSE 表达式

检查变量abc和xyz的值是否匹配,并显示结果,即150

postgres=# Do 
             $$
             Declare
              abc int;
              xyz int;
              begin
              abc:=100;
              xyz:=abc;
              if abc=xyz then 
               xyz=150;  
              raise notice '%',xyz;
             else
             end if;               
             end;
               $$
;
NOTICE:  150
DO

26. 使用join更新

如果我们要更新表X,但是需要基于另外一张表Y,我们可以按下面这样使用:

postgres=# create table X(n int, n1 char(10));
CREATE TABLE
postgres=# insert into X values (1,'abc');
INSERT 0 1
postgres=# insert into X values (2,'xyz');
INSERT 0 1
postgres=# insert into X values (3,'pqr');
INSERT 0 1

postgres=# create table Y(n int, n1 char(10));
CREATE TABLE

postgres=# insert into Y values (1,'');
INSERT 0 1
postgres=# insert into Y values (2,'');
INSERT 0 1

postgres=# insert into Y values (5,'axyz');
INSERT 0 1

postgres=# update Y set n1=X.n1 from X  where X.n=Y.n;
UPDATE 2
postgres=# select * from Y;
 n |     n1     
---+------------
 5 | axyz      
 1 | abc       
 2 | xyz       
(3 rows)

postgres=# 

27. inner join

将从两个(或多个)表中查找表中指定列数据匹配的行

postgres=# select *  from x inner join  y on  x.n1 = y.n1;
 n |     n1     | n |     n1     
---+------------+---+------------
 1 | abc        | 1 | abc       
 2 | xyz        | 2 | xyz       
(2 rows)

postgres=# 

28. case表达式

CASE表达式是通用条件表达式,类似于IF…ELSE语句。

postgres=# SELECT age,
       CASE age WHEN 25 THEN 'one'
              WHEN 50 THEN 'two'
              ELSE 'other'
       END
    FROM  dummy_table;
 age | case  
-----+-------
  25 | one
  35 | other
  40 | other
  50 | two
  50 | two
(5 rows)

29. 递归查询

递归查询用于处理层次查询或树状数据,下面创建测试数据:

CREATE TABLE emp_test (
  id int,
  ename varchar(255),
  emanager int
);

INSERT INTO emp_test VALUES (1, 'abc', null);
INSERT INTO emp_test VALUES (2, 'xyz', 1);
INSERT INTO emp_test VALUES (3, 'def', 2);
INSERT INTO emp_test VALUES (4, 'cde', 1);
INSERT INTO emp_test VALUES (5, 'qrs', 2);
INSERT INTO emp_test VALUES (9, 'iop', 3);
INSERT INTO emp_test VALUES (10, 'klm', 4);

递归查询如下:

postgres=#WITH RECURSIVE emp_testnew  AS (
  SELECT id, ename, emanager
  FROM emp_test
  WHERE id = 2
  UNION ALL
  SELECT e.id, e.ename, e.emanager
  FROM emp_test e
  INNER JOIN emp_testnew e1 ON e1.id = e.emanager
)
SELECT *
FROM emp_testnew;

 id | ename | emanager 
----+-------+----------
  2 | xyz   |        1
  3 | def   |        2
  5 | qrs   |        2
  9 | iop   |        3
(4 rows)

postgres=# 

30. log查询

使用pg_stat_statements模块,我们可以跟踪所有SQL语句的执行统计信息。 为此,我们需要创建一个扩展并在postgresql.conf文件内添加shared_preload_libraries

postgres=# create extension pg_stat_statements;
CREATE EXTENSION


postgres=# show shared_preload_libraries ;
                           shared_preload_libraries                           
-------------------------------------------------
 $libdir/pg_stat_statements
(1 row)


postgres=# select query from pg_stat_statements where query like 'create table%';
-[ RECORD 1 ]-------------------
query | create table test(n int)

我们还可以通过启用postgresql.conf文件中的以下参数来配置PostgreSQL以生成日志输出

logging_collector = on
log_directory = 'log'
log_filename = ‘postgresql-%Y-%m-%d_%H%M%S.log'
log_destination = ‘stderr’
Log file will be created under the pg_log directory which resides under the data folder. 

[centos@tushar-ldap-docker bin]$ ls  data/log
postgresql-2020-09-17_150932.log  postgresql-2020-09-19_000000.log  
[centos@tushar-ldap-docker bin]$ 

查询记录的日志将被记录在这些文件中。

31. 使用变量

我们可以在psql prompt下使用声明变量:

postgres=# \set cond 50

在where条件中使用变量

postgres=# select * from dummy_table where age=:cond;
 name |  address   | age 
------+------------+-----
 PQR  | location-D |  50
(1 row)

postgres=# \set cond 50
postgres=# select :cond+100 ;
 ?column? 
----------
      150
(1 row)

32. 日期查询

详细:https://www.postgresql.org/docs/12/functions-datetime.html

postgres=# select now();
               now                
----------------------------------
 22-SEP-20 03:08:42.636385 +05:30
(1 row)

postgres=# select current_date;
 current_date 
--------------
 22-SEP-20
(1 row)

postgres=# select current_time;
     current_time      
-----------------------
 03:08:53.648466+05:30
(1 row)

我们还可以执行日期范围查询来查找值在两个时间戳之间的行:

postgres=# create table datetable(n int,n1 date);
CREATE TABLE

postgres=# insert into datetable values (1,'12-01-1980');
INSERT 0 1
postgres=# insert into datetable values (2,'12-01-2020');
INSERT 0 1
postgres=# insert into datetable values (3,'12-01-2000');
INSERT 0 1
postgres=# select * from datetable where n1 between '12-01-1980' and '12-01-2000';
 n |         n1         
---+--------------------
 1 | 12-JAN-80 00:00:00
 3 | 12-JAN-00 00:00:00
(2 rows)

33. return query

当声明一个PL / pgSQL函数返回某个数据类型的SETOF时,该返回由RETURN QUERY命令指定

postgres=# CREATE FUNCTION get(int) RETURNS SETOF integer AS
$BODY$
BEGIN
    RETURN QUERY SELECT age
                   FROM dummy_table
                  WHERE age >= $1  ;
    RETURN;
 END
$BODY$
LANGUAGE plpgsql;


postgres=# select * from get(9);
 get 
-----
  25
  35
  40
  50
(4 rows)

34. 并行查询

PostgreSQL中的并行查询使您可以利用许多CPU更快地完成查询。 这些GUC参数在postgresql.conf文件中设置

#max_parallel_maintenance_workers = 2   # taken from max_parallel_workers
#max_parallel_workers_per_gather = 2    # taken from max_parallel_workers
#parallel_leader_participation = on
#max_parallel_workers = 8               # maximum number of max_worker_processes that
                                                           # can be used in parallel operations


postgres=# create table ty(n int);
CREATE TABLE
postgres=# insert into ty values (generate_series(1,300000));
INSERT 0 300000

postgres=# analyze ty;
ANALYZE
postgres=# explain  select * from ty where n<=1;
                             QUERY PLAN                              
---------------------------------------------------------------------
 Gather  (cost=1000.00..4536.88 rows=30 width=4)
   Workers Planned: 1
   ->  Parallel Seq Scan on ty  (cost=0.00..3533.88 rows=18 width=4)
         Filter: (n <= 1)
(4 rows)

postgres=# 

35. 逻辑运算符

postgreSQL中有三个主要的逻辑运算符:AND OR NOT。

AND = when both boolean expressions are true then it will return TRUE
OR   = when any boolean expression is true then it will return TRUE
NOT = reverses the value of Boolean operator

36. 捕获重复的行

下面这个查询有两个重复的50:

 postgres=# select age from dummy_table;
 age 
-----
  25
  35
  40
  50
  50
(5 rows)

我们可以利用select ... having来找到重复的行。

postgres=#  select age, count(age) from dummy_table group by age having count(age)>1;
 age | count 
-----+-------
  50 |     2
(1 row)

37. 枚举

枚举类型是包含静态的,有序的一组值的数据类型。

postgres=# CREATE TYPE mood AS ENUM ('sad', 'ok', 'happy');
CREATE TYPE
postgres=# create table testi(n int, n1 mood);
CREATE TABLE
postgres=# insert into testi values (1,'happy');
INSERT 0 1
postgres=# insert into testi values (1,'sad');
INSERT 0 1
postgres=# insert into testi values (1,'ok');
INSERT 0 1

如果enum没有被指定,将会报错:

postgres=# insert into testi values (1,'happyo');
ERROR:  invalid input value for enum mood: "happyo"

38. pivot table

是一种通过将数据组织成更易于管理的格式来分析大量数据的有用方法。

CREATE TABLE newtb(id SERIAL, rowid varchar(10), attri varchar(10), val varchar(10));
INSERT INTO newtb(rowid, attri, val) values('t1','a1','v1');
INSERT INTO newtb(rowid, attri, val) values('t1','a2','v2');
INSERT INTO newtb(rowid, attri, val) values('t1','a3','v3');
INSERT INTO newtb(rowid, attri, val) values('t1','a4','v4');
INSERT INTO newtb(rowid, attri, val) values('t2','a1','v5');
INSERT INTO newtb(rowid, attri, val) values('t2','a2','v6');
INSERT INTO newtb(rowid, attri, val) values('t2','a3','v7');
INSERT INTO newtb(rowid, attri, val) values('t2','a4','v8');

创建pivot table,你需要安装 tablefunc extension:

postgres=# create extension tablefunc;
CREATE EXTENSION

Select *
FROM crosstab(
  'select rowid, attri, val
   from newtb
   where attri = ''a2'' or attri = ''a3''
   order by 1,2')
AS newtb(row_name varchar(10), category_1 varchar(10), category_2 varchar(10), category_3 varchar(10));
 row_name | category_1 | category_2 | category_3 
----------+------------+------------+--------------------------
   t1       |              v2        |            v3    | 
   t2       |             v6         |             v7   | 
(2 rows)

39. self join自连接

当我们针对自身联接表时,这称为自联接。 可以使用INNER JOINLEFT JOIN完成。 当比较同一表中的行时,自连接非常有用。

postgres=# create table emp1(emp_id int, firstname char(10), lastname char(10) , manager_id int);
CREATE TABLE
postgres=# 
postgres=# 
postgres=# insert into emp1 values(1,'ABC','XYZ',NULL);
INSERT 0 1
postgres=# insert into emp1 values(2,'TYU','BGV',1);
INSERT 0 1
postgres=# insert into emp1 values(3,'TEU','ZZV',1);
INSERT 0 1
postgres=# insert into emp1 values(4,'REU','AZV',2);
INSERT 0 1
postgres=# insert into emp1 values(5,'QREU','WZV',2);
INSERT 0 1
postgres=# insert into emp1 values(6,'DREU','QZV',3);
INSERT 0 1


postgres=# select a.firstname,b.lastname from emp1 a inner join emp1 b on a.emp_id=b.manager_id order by 1 ;
 firstname  |  lastname  
------------+------------
 ABC        | ZZV       
 ABC        | BGV       
 TEU        | QZV       
 TYU        | WZV       
 TYU        | AZV       
(5 rows)

postgres=# 

40. 父子递归

依靠 common table expressions (CTE),我们可以进行父子查询。

postgres=# CREATE TABLE recu_pc (
 id SERIAL PRIMARY KEY,
 name varchar(10) NOT NULL,
 parent_id integer );
CREATE TABLE
 
postgres=# insert into recu_pc values (1, 'Grandmother', NULL);
INSERT 0 1
postgres=# insert into recu_pc values (2, 'mother', 1);
INSERT 0 1
postgres=# insert into recu_pc values (3, 'daughter', 2);
INSERT 0 1

 
postgres=# WITH RECURSIVE rec_q (id) as
(          
  SELECT recu_pc.id, recu_pc.name from recu_pc where name='mother'
  UNION ALL
  SELECT recu_pc.id, recu_pc.name from rec_q, recu_pc where recu_pc.parent_id = rec_q.id
  )
SELECT *
FROM rec_q;
 id |   name   
----+----------
  2 | mother
  3 | daughter
(2 rows)

41. 定义变量

使用匿名块 anonymous block,我们可以定义传入query的变量

postgres=# do 
$$
declare 
a int;
begin 
select age into a from dummy_table  
where name ='XYZ';
raise notice '%',a; 
end;
$$;
NOTICE:  25
DO

42. prepare语句

用于优化性能。 当执行PREPARE语句时,不仅会对其进行解析,而且还会对其进行分析,并且当我们执行EXECUTE命令时,将计划并执行准备好的语句。

postgres=# prepare test(int) as 
select * from dummy_table where age=$1;
PREPARE
 
postgres=# execute test(50);
 name |  address   | age 
------+------------+---------
 PQR  | location-D |  50
 CXC | 1                |  50
(2 rows)

43. 检查null值

postgres=# select * from dummy_table;
 name |  address   | age 
------+------------+-----
 XYZ  | location-A |  25
 ABC  | location-B |  35
 DEF  | location-C |  40
 PQR  | location-D |  54
 PQR  | location-D |    
(5 rows)

找到age值为null的记录

postgres=# select name from dummy_table where age is null;
 name 
------
 PQR
(1 row)

44. 使用exists检查查询是否为空

我们可以使用EXISTS检查查询是否为空。 EXISTS是一个布尔运算符,用于测试子查询中行的存在。

postgres=# select exists(select * from (select 'true' where 1=3));
 exists 
--------
 f
(1 row)

postgres=# select exists(select * from (select 'true' where 1=1));
 exists 
--------
 t
(1 row)

45. 语句执行时间日志

要查看查询的执行时间日志,您需要启用相关的GUC参数:

postgresql=# set log_min_duration_statement=0;
SET
postgresql=# set log_statement='all';
SET

现在,如果我们检查在data / log文件夹中创建的日志文件,我们应该会收到执行时间消息

2020-09-23 02:47:12.887 +0530 [30737] LOG:  statement: create table gg1(n int);
2020-09-23 02:47:12.888 +0530 [30737] LOG:  duration: 1.165 ms
2020-09-23 02:47:28.092 +0530 [30737] LOG:  statement: insert into gg1 values (generate_series(1,100000));
2020-09-23 02:47:28.182 +0530 [30737] LOG:  duration: 94.858 ms 

46. 在shell脚本中执行查询

我们可以使用bash shell脚本执行psql命令。 下面的示例是一个print.sh文件,我们在其中执行两个数字的加法运算

[edb@tushar-ldap-docker misc]$ cat print.sh 
#!/bin/bash
# This script is used to print addition of 2 numbers
# 1. Get path of bin directory.
BIN_DIRECTORY='/usr/psql-11/bin/'
$BIN_DIRECTORY/psql -U  postgres -p 5432 -d postgres -c 'select  5+5;'

执行脚本

edb@tushar-ldap-docker misc]$ print.sh 
 ?column? 
----------
       10
(1 row)

47. union操作符

用于合并两个或多个SQL语句的结果,同时消除重复的行。

postgres=# create table tab1(n int); 
CREATE TABLE

postgres=# insert into tab1 values (1),(2);
INSERT 0 2
postgres=# create table tab2(n int); 
CREATE TABLE

postgres=# insert into tab2 values (3),(2);
INSERT 0 2

postgres=# select * from tab1 union select * from tab2;
 n 
---
 2
 1
 3
(3 rows)

48. 查询优化的命令

explain

explain命令显示一条语句的执行计划。 在explain计划中添加analyze关键字将执行查询并显示真实的行数和真实的运行时间

vacuum

vacuum命令基本上删除所有由update删除或过时但未从表中物理删除的元组。

analyze

analyze收集有关数据库中表内容的统计信息

Database indexes

创建数据库索引可以避免全表扫描。

PostgreSQL configuration parameters

我们可能会使用某些PostgreSQL配置参数来获得更好的性能,例如max_connectionscheckpoint_segmentswork_mem和random_page_cost

49. alter table添加或修改列

添加或修改列

postgres=# alter table dummy_table add col1 int;
ALTER TABLE
postgres=# alter table dummy_table  rename col1 to col2;
ALTER TABLE
postgres=#  alter table dummy_table alter column col2 type char;
ALTER TABLE
postgres=# alter table dummy_table drop column col2;
ALTER TABLE

50. comment注释

使用comment语句提供有关数据库对象的注释

postgres=# Comment on table dummy_table  is 'This was a testing table';
COMMENT

postgres=# Comment on function f is 'Don''t update the function please' ;
COMMENT

你可能感兴趣的:(数据库,postgresql)