PostgreSQL入门教程

image

PostgreSQL介绍

什么是PostgreSQL

PostgreSQL是一个功能强大的开源对象关系数据库管理系统(ORDBMS)。 用于安全地存储数据; 支持最佳做法,并允许在处理请求时检索它们。

PostgreSQL是跨平台的,可以在许多操作系统上运行,如Linux,FreeBSD,OS X,Solaris和Microsoft Windows等。

常用于联机事务处理OLTP(on-line transaction processing)、联机分析处理OLAP(On-Line Analytical Processing)。

PostgreSQL特点

  • 稳定

得益于PostgreSQL的多进程架构,一个连接的异常并不影响主进程和其他连接,从而带来不错的稳定性

  • 高性能

TPCC的性能测试显示PostgreSQL的性能与商业数据库基本在同一个层面上

  • 丰富

查询丰富:且不说HASH\Merge\NestLoop JOIN,还有递归、树形(connect by)、窗口、rollup\cube\grouping sets、物化视图、SQL标准等,还有各种全文检索、正则表达式、模糊查询、相似度等。在这些之外,最重要的是PostgreSQL强大的基于成本的优化器,结合并行执行(并行扫瞄、并行JOIN等)和多种成本因子,带来各种各样丰富灵活高效的查询支持。

类型丰富:如高精度numeric, 浮点, 自增序列,货币,字节流,时间,日期,时间戳,布尔, 枚举,平面几何,立体几何,多维几何,地球,PostGIS,网络,比特流,全 文检索,UUID,XML,JSON,数组,复合类型,域类型,范围,树类型,化 学类型,基因序列,FDW, 大对象, 图像等。

[PS: 这里的数组,可以让用户像操作JAVA中的数组一样操作数据库中的数据,如 item[0][1]即表示二维数组中的一个元素,而item可以作为表的一个字段。]

或者,如果以上不够满足,你可以自定义自己的类型(create type),并且可以针对这些类型进行运算符重载,比如实现IP类型的加减乘除(其操作定义依赖于具体实现,意思是:你想让IP的加法是什么样子就是什么样子)。

另外还有各种索引的类型,如btree, hash, gist, sp-gist, gin, brin , bloom , rum 索引等。你甚至可以为自己定义的类型定制特定的索引和索引扫瞄。

功能丰富:PostgreSQL有一个无与伦比的特性——插件。其利用内核代码中的Hook,可以让你在不修改数据库内核代码的情况下,自主添加任意功能,如PostGIS、JSON、基因等,都是在插件中做了很多的自定义而又不影响任何内核代码从而满足丰富多样的需求。而PostgreSQL的插件,不计其数

FDW机制更让你可以在同一个PostgreSQL中像操作本地表一样访问其他数据源,如Hadoop、MySQL、Oracle、Mongo等,且不会占用PG的过多资源。比如阿里开发的OSS_FDW就用于实现对OSS的读写

PostgreSQL语法

PostgreSQL支持大部分SQL:2011特性[1]。
psql中可以使用\help命令查看所有PostgreSQL语句的语法。使用\help &可查看特定语句语法。

postgres=# \help WITH
Command:     WITH
Description: retrieve rows from a table or view
Syntax:
[ WITH [ RECURSIVE ] with_query [, ...] ]
SELECT [ ALL | DISTINCT [ ON ( expression [, ...] ) ] ]
    [ * | expression [ [ AS ] output_name ] [, ...] ]
    [ FROM from_item [, ...] ]
    [ WHERE condition ]
    [ GROUP BY grouping_element [, ...] ]
    [ HAVING condition [, ...] ]
    [ WINDOW window_name AS ( window_definition ) [, ...] ]
    [ { UNION | INTERSECT | EXCEPT } [ ALL | DISTINCT ] select ]
    [ ORDER BY expression [ ASC | DESC | USING operator ] [ NULLS { FIRST | LAST } ] [, ...] ]
    [ LIMIT { count | ALL } ]
    [ OFFSET start [ ROW | ROWS ] ]
    [ FETCH { FIRST | NEXT } [ count ] { ROW | ROWS } ONLY ]
    [ FOR { UPDATE | NO KEY UPDATE | SHARE | KEY SHARE } [ OF table_name [, ...] ] [ NOWAIT | SKIP L
OCKED ] [...] ]
  • INSERT
  • SELECT
  • UPDATE
  • DELETE
  • ORDER BY子句
  • GROUP BY子句
  • HAVING子句
  • WHERE条件查询
  • 表连接

https://www.yiibai.com/postgresql/postgresql-syntax.html

PostgreSQL常用函数及操作符

字符串函数及操作符

  • ||
语句 结果
'Value: ' || 42 Value: 42
'String' || null null
  • concat(), concat_ws()
语句 结果
concat('abc', null, 22) abc22
concat_ws(',', 'abc', null, 33) abc,33
  • position()
语句 结果
position('om' in 'Thomas') 3
  • substring()
语句 结果
substring('Thomas' from 2 for 3) hom
substring('Thomas' from '^..') Th

https://www.postgresql.org/docs/10/static/functions-string.html

模式匹配

  • LIKE

全量匹配(除非有%符号)

语句 结果
'abc' LIKE '_b%' t
'abc' NOT LIKE '%c' f
  • SIMILAR TO正则表达式

借用LIKE和部分POSIX正则表达式,全量匹配(除非有%符号)

可用的POSIX正则表达式:| * + ? {m} {m,} {m,n}

语句 结果
'abc' SIMILAR TO 'a' f
'abc' SIMILAR TO '%(b|d)%' t
'abc' SIMILAR TO '(b|c)%' f
  • POSIX正则表达式
语句 结果
'thomas' ~ '.*thomas.*' t
'thomas' ~* '.*Thomas.*' t
'thomas' !~ '.*Thomas.*' t
'thomas' !~* '.*vadim.*' t

https://www.postgresql.org/docs/10/static/functions-matching.html

数据类型格式化函数

  • to_char()
语句 结果
to_char(current_timestamp, 'HH24:MI:SS') 07:34:48
to_char(-0.1, '99.99') ' -.10'
to_char(1::numeric/2::numeric, 'FM990.00'); '0.50'
  • to_date()
语句 结果
to_date('05 Dec 2000', 'DD Mon YYYY') 2000-12-05
  • to_number()
语句 结果
to_number('12,454.8-', '99G999D9S') -12454.8
  • to_timestamp()
语句 结果
to_timestamp('05 Dec 2000', 'DD Mon YYYY') 2000-12-05 00:00:00+00

日期、时间操作符及函数

  • + - * /
语句 结果
date '2001-09-28' + integer '7' date '2001-10-05'
date '2001-09-28' + time '03:00' timestamp '2001-09-28 03:00:00'
date '2001-09-28' - interval '1 hour' timestamp '2001-09-27 23:00:00'
900 * interval '1 second' interval '00:15:00'
interval '1 hour' / double precision '1.5' interval '00:40:00'
  • current_date, current_time, current_timestamp

  • date_part()

语句 结果
date_part('hour', timestamp '2001-02-16 20:38:40') 20
date_part('month', interval '2 years 3 months') 3
  • make_date(), make_time(), make_timestamp()
语句 结果
make_date(2013, 7, 15) date '2013-07-15'
make_time(8, 15, 23.5) time '08:15:23.5'
make_timestamp(2013, 7, 15, 8, 15, 23.5) timestamp '2013-07-15 08:15:23.5'

条件表达式

  • CASE
CASE WHEN condition THEN result
     [WHEN ...]
     [ELSE result]
END
CASE expression
    WHEN value THEN result
    [WHEN ...]
    [ELSE result]
END
  • COALESCE
COALESCE(value [, ...])
  • NULLIF
NULLIF(value1, value2)
语句 结果
SELECT CASE WHEN 3>2 THEN 'A' ELSE 'B' END 'A'
SELECT COALESCE(NULL,'A','B') 'A'
SELECT NULLIF('A','A') NULL
SELECT NULLIF('A','B') 'A'

聚集函数

  • avg,count,max,min,sum

集合生成函数

  • generate_series()
SELECT * FROM generate_series(2,4);
 generate_series
-----------------
               2
               3
               4
(3 rows)

SELECT generate_series(1.1, 4, 1.3);
 generate_series 
-----------------
             1.1
             2.4
             3.7
(3 rows)

SELECT * FROM generate_series('2008-03-01 00:00'::timestamp, '2008-03-02 12:00', '10 hours');
   generate_series
---------------------
 2008-03-01 00:00:00
 2008-03-01 10:00:00
 2008-03-01 20:00:00
 2008-03-02 06:00:00
(4 rows)

with子句(通用数据表表达式)

辅助报表与查询

WITH regional_sales AS (
    SELECT region, SUM(amount) AS total_sales
    FROM orders
    GROUP BY region
), top_regions AS (
    SELECT region
    FROM regional_sales
    WHERE total_sales > (SELECT SUM(total_sales)/10 FROM regional_sales)
)
SELECT region,
       product,
       SUM(quantity) AS product_units,
       SUM(amount) AS product_sales
FROM orders
WHERE region IN (SELECT region FROM top_regions)
GROUP BY region, product;

数据修改语句

WITH moved_rows AS (
    DELETE FROM products
    WHERE
        "date" >= '2010-10-01' AND
        "date" < '2010-11-01'
    RETURNING *
)
INSERT INTO products_log
SELECT * FROM moved_rows;

自定义函数及plpgsql

语法

CREATE [OR REPLACE] FUNCTION function_name(参数逗号隔开) 
RETURNS 返回值类型 AS $body$
    DECLARE //声明变量
        变量名 变量类型 :=变量值;
        例如:name char(20):='su';
    BEGIN  
        /*函数体;包括DML语句;
        特别注意:如果有返回值,要省略最后的return语句的话,则在函数体的最后必须是一个select语句且返回类型必须和上面声明的类型一样;
        */
        RETURN 变量名//和上面返回的变量一样;
    END
    $body$
LANGUAGE plpgsql;

示例

create or replace function f_test() returns void as $$
declare
    begin
        for i in 1..1000 loop
            execute 'insert into test select generate_series('||(i-1)*40000+1||','||i*40000||'),(random()::float)*'||i*0.0001||',clock_timestamp()';
        end loop;
    end;
$$ language plpgsql;

PostgreSQL实战

自增主键的实现

  • 使用Sequence
CREATE SEQUENCE users_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
 
alter table users alter column id set default nextval('users_id_seq');
  • 使用serial
CREATE TABLE users
(
id SERIAL primary key ,
name character varying,
password character varying
)

PostgreSQL会自动创建名为users_id_seq的序列,且MAXVALUE=2^63-1

多字段去重统计的实现

MySQL中可以使用COUNT(DISTINCT expr,[expr...])统计多字段不同值的非空行数

PostgreSQL可以使用如下方式实现:

SELECT count(DISTINCT column1||'@'||column2) from table;

进阶

  • 索引[2]

多列索引、复合索引、gin、bloom、前后模糊查询、正则查询

  • 相似度分析[3]

相近、相仿、距离接近、性格接近等等类似这样的需求,对数据进行筛选

  • 全文检索[4]

参考资料

官方文档:https://www.postgresql.org/docs/10/static/index.html

https://www.yiibai.com/postgresql

[1]https://www.postgresql.org/docs/10/static/features.html

[2]https://github.com/digoal/blog/blob/master/201612/20161231_01.md
https://github.com/digoal/blog/blob/master/201702/20170205_01.md

[3]https://yq.aliyun.com/articles/59212
[4]https://www.postgresql.org/docs/10/static/functions-textsearch.html
http://blog.chinaunix.net/uid-20726500-id-4820580.html

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,524评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,869评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,813评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,210评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,085评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,117评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,533评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,219评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,487评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,582评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,362评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,218评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,589评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,899评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,176评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,503评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,707评论 2 335

推荐阅读更多精彩内容

  • 关于Mongodb的全面总结 MongoDB的内部构造《MongoDB The Definitive Guide》...
    中v中阅读 31,863评论 2 89
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,497评论 18 139
  • 转 # https://www.cnblogs.com/easypass/archive/2010/12/ 08/...
    吕品㗊阅读 9,681评论 0 44
  • 八月参加了小鹿的21天早餐馆打卡,学到了许多关于早餐制作和手机拍照的知识,也结交了许多热爱生活的小伙伴。 始终相信...
    刘元元阅读 271评论 4 7
  • 【写在前面】 衡量一个人是否聪明的标准:大脑里是否有足够多清晰、准确、正确的概念,这些概念是否有清晰、准确、正确的...
    废材小丢丢阅读 340评论 0 0