添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

目录

翻译自原文链接: 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 
    ---------
    (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;
    -----
    (5 rows)
    
    postgres=# select distinct age from dummy_table order by 1;
    -----
    (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;
    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;
    (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;
    -----
    (4 rows)
    

    在where中使用ilike查询

    postgres=# select * from ted where n ilike '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
    (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 
    begin 
    perform
    now(); 
     return 1; 
    $$ language 'plpgsql';
    CREATE FUNCTION
    postgresql=# select f(9);
    (1 row)
    

    在select into语句中使用变量

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

    23. count计数

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

    postgres=# select count(*) from dummy_table;
     count 
    -------
    (1 row)
    postgres=# select count(avg) from dummy_table;
     count 
    -------
    (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;
                 end if;               
    NOTICE:  150
    

    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'
        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? 
    ----------
    (1 row)
    

    32. 日期查询

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

    postgres=# select 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;
    $BODY$
    LANGUAGE plpgsql;
    postgres=# select * from get(9);
    -----
    (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;
    -----
    (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; 
    NOTICE:  25
    

    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;
    ------
    (1 row)
    

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

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

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

    45. 语句执行时间日志

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

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

    现在,如果我们检查在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? 
    ----------
    (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;
    (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