因为有很不错的Mysql和Oracle的底子就不写那些无聊的了。
看了介绍后的感觉
一个有对象概念的关系型数据库,与其说是关系型数据库,倒不如说更像Elasticsearch那种NoSQL。他的对象观念让存的数据更加多元化了。我相信他在ORM上面应该有更大的优势,但是我目前也只是初见初步使用,暂时没有看出来优势。
新特性
特别的数据类型
枚举类型
有点类似oracle的赋值限制,不过建法不同。
CREATE TYPE mood AS ENUM ('sad', 'ok', 'happy');
几何类型
神他瞄几何类型,这个东西就是为了方便计算后期加入正式版的自定义类型吧。。。自己写函数和自定义类型不好吗,多此一举,搞啥标准化。下面好多都是这样的,看得人心累┓(;´_`)┏
名字 | 存储空间 | 说明 | 表现形式 |
---|---|---|---|
point | 16 字节 | 平面中的点 | (x,y) |
line | 32 字节 | (无穷)直线(未完全实现) | ((x1,y1),(x2,y2)) |
lseg | 32 字节 | (有限)线段 | ((x1,y1),(x2,y2)) |
box | 32 字节 | 矩形 | ((x1,y1),(x2,y2)) |
path | 16+16n 字节 | 闭合路径(与多边形类似) | ((x1,y1),...) |
path | 16+16n 字节 | 开放路径 | [(x1,y1),...] |
polygon | 40+16n 字节 | 多边形(与闭合路径相似) | ((x1,y1),...) |
circle | 24 字节 | 圆 | <(x,y),r> (圆心和半径) |
网络地址类型
提供基本校验功能而已的文本
名字 | 存储空间 | 描述 |
---|---|---|
cidr | 7 或 19 字节 | IPv4 或 IPv6 网络 |
inet | 7 或 19 字节 | IPv4 或 IPv6 主机和网络 |
macaddr | 6 字节 | MAC 地址 |
文本搜索类型
拆分文本?文本检索?为嘛数据库会来做这个操作?我懵逼了,我是难以理解这东西是干嘛的,难道能方便网页做搜索功能?
UUID
标准基于RFC 4122,ISO/IEF 9834-8:2005
一般来说不做分布式是不会用的,还有是不是现代社会进步了,都开始使用数据库掌控数据唯一性了。。。脑子大。
XML 类型
使用函数 xmlparse: 来从字符数据产生 xml 类型的值:
XMLPARSE (DOCUMENT '
') Manual ...
XMLPARSE (CONTENT 'abcbar foo ')
JSON类型
json 数据类型可以用来存储 JSON(JavaScript Object Notation)数据, 这样的数据也可以存储为 text,但是 json 数据类型更有利于检查每个存储的数值是可用的 JSON 值。
此外还有相关的函数来处理 json 数据:
实例 | 实例结果 |
---|---|
array_to_json('{{1,5},{99,100}}'::int[]) | [[1,5],[99,100]] |
row_to_json(row(1,'foo')) | {"f1":1,"f2":"foo"} |
数组类型
唯一一个我觉得不错的,毕竟原先我知道的只在procedure里面才支持数组。还是很有用的(存个表不好吗,写这个数据库的是不是太懒了!?)
CREATE TABLE sal_emp (
name text,
pay_by_quarter integer[],
schedule text[][]
);
复合类型
从这个开始就有对象的味道了,也有了ES的味道。这个其实就是struct
CREATE TYPE complex AS (
r double precision,
i double precision
);
CREATE TYPE inventory_item AS (
name text,
supplier_id integer,
price numeric
);
范围类型
不能说没用,写这个数据库的连设定个起止时间都不高兴吗?有毒,真的有。不过B-树居然能利用到范围变量里面去。。。我还是智商不行。
- int4range — integer的范围
- int8range —bigint的范围
- numrange —numeric的范围
- tsrange —timestamp without time zone的范围
- tstzrange —timestamp with time zone的范围
- daterange —date的范围
事务
默认postgres是自动开启事务并提交的,挺讨厌的,会导致误操作。所以最好用户自己去控制,并养成习惯:
BEGIN;
UPDATE accounts SET balance = balance - 100.00
WHERE name = 'Alice';
SAVEPOINT my_savepoint;
UPDATE accounts SET balance = balance + 100.00
WHERE name = 'Bob';
-- oops ... forget that and use Wally's account
ROLLBACK TO my_savepoint;
UPDATE accounts SET balance = balance + 100.00
WHERE name = 'Wally';
COMMIT;
继承
卧槽,继承。。。。。。。。。行吧,你厉害
CREATE TABLE cities (
name text,
population real,
altitude int -- (in ft)
);
CREATE TABLE capitals (
state char(2)
) INHERITS (cities);
其实就是查询父表会把子表带出来轮一遍,可以用ONLY关键词限制深入
写法
U&""
16进制Unicode字符
UESCAPE
将后面的字符当做转义字符看,默认是''
'Dianne''s horse'
将两个单引号看做文本本来有的单引号。。。
不转义的方式
$$Dianne's horse$$
$SomeTag$Dianne's horse$SomeTag$
E'foo'
C风格转义的字符串常量
B'1001'或X'1FF'
二进制或者十六进制的位串常量
其他类型的变量
type 'string'
'string'::type
CAST ( 'string' AS type )
这其实是一个类型转换
特殊字符
懒了,复制粘贴
一些不是数字字母的字符有一种不同于作为操作符的特殊含义。这些字符的详细用法可以在描述相应语法元素的地方找到。这一节只是为了告知它们的存在以及总结这些字符的目的。
跟随在一个美元符号(
$
)后面的数字被用来表示在一个函数定义或一个预备语句中的位置参数。在其他上下文中该美元符号可以作为一个标识符或者一个美元引用字符串常量的一部分。圆括号(
()
)具有它们通常的含义,用来分组表达式并且强制优先。在某些情况中,圆括号被要求作为一个特定 SQL 命令的固定语法的一部分。方括号(
[]
)被用来选择一个数组中的元素。更多关于数组的信息见第 8.15 节。逗号(
,
)被用在某些语法结构中来分割一个列表的元素。分号(
;
)结束一个 SQL 命令。它不能出现在一个命令中间的任何位置,除了在一个字符串常量中或者一个被引用的标识符中。冒号(
:
)被用来从数组中选择“切片”(见第 8.15 节)。在某些 SQL 的“方言”(例如嵌入式 SQL)中,冒号被用来作为变量名的前缀。星号(
*
)被用在某些上下文中标记一个表的所有域或者组合值。当它被用作一个聚集函数的参数时,它还有一种特殊的含义,即该聚集不要求任何显式参数。句点(
.
)被用在数字常量中,并且被用来分割模式、表和列名。
表 4.2. 操作符优先级(从高到低)
操作符/元素 | 结合性 | 描述 |
---|---|---|
. | 左 | 表/列名分隔符 |
:: | 左 | PostgreSQL-风格的类型转换 |
[ ] | 左 | 数组元素选择 |
+ - | 右 | 一元加、一元减 |
^ | 左 | 指数 |
* / % | 左 | 乘、除、模 |
+ - | 左 | 加、减 |
(任意其他操作符) | 左 | 所有其他本地以及用户定义的操作符 |
BETWEEN IN LIKE ILIKE SIMILAR | 范围包含、集合成员关系、字符串匹配 | |
< > = <= >= <> | 比较操作符 | |
IS ISNULL NOTNULL | IS TRUE、IS FALSE、IS NULL、IS DISTINCT FROM等 | |
NOT | 右 | 逻辑否定 |
AND | 左 | 逻辑合取 |
OR | 左 | 逻辑析取 |
值表达式
(compositecol).somefield
为嘛要加一个圆括号?因为需要限制compositecol是一个列名而不是一个表名,下面则是则是显示mytable是一个表名而不是一个模式名。
(mytable.compositecol).somefield
这其实是一个挺讨人厌的性质。正是因为拥有自定义类型导致整个结构表述出现了一些特殊约定。
排序规则表达式
一个脑子大的关键词,自己玩去吧
PostgreSQL 字符串 collate 与排序 源码分析
行构造器
ROW('fuzzy dice', 42, 1.99)
类似复合类型但是不能混用(他被叫做匿名混合类型),哈哈,具体可以看下文
CREATE TABLE mytable(f1 int, f2 float, f3 text);
CREATE FUNCTION getf1(mytable) RETURNS int AS 'SELECT $1.f1' LANGUAGE SQL;
-- 不需要造型因为只有一个 getf1() 存在
SELECT getf1(ROW(1,2.5,'this is a test'));
getf1
-------
1
(1 row)
CREATE TYPE myrowtype AS (f1 int, f2 text, f3 numeric);
CREATE FUNCTION getf1(myrowtype) RETURNS int AS 'SELECT $1.f1' LANGUAGE SQL;
-- 现在我们需要一个造型来指示要调用哪个函数:
SELECT getf1(ROW(1,2.5,'this is a test'));
ERROR: function getf1(record) is not unique
SELECT getf1(ROW(1,2.5,'this is a test')::mytable);
getf1
-------
1
(1 row)
SELECT getf1(CAST(ROW(11,'this is a test',2.5) AS myrowtype));
getf1
-------
11
(1 row)
一个有趣的提示
子表达式的计算顺序没有被定义。特别地,一个操作符或函数的输入不必按照从左至右或其他任何固定顺序进行计算。
此外,如果一个表达式的结果可以通过只计算其一部分来决定,那么其他子表达式可能完全不需要被计算。例如,如果我们写:
SELECT true OR somefunc();
那么somefunc()
将(可能)完全不被调用。如果我们写成下面这样也是一样:
SELECT somefunc() OR true;
注意这和一些编程语言中布尔操作符从左至右的“短路”不同。
因此,在复杂表达式中使用带有副作用的函数是不明智的。在WHERE
和HAVING
子句中依赖副作用或计算顺序尤其危险,因为在建立一个执行计划时这些子句会被广泛地重新处理。这些子句中布尔表达式(AND
/OR
/NOT
的组合)可能会以布尔代数定律所允许的任何方式被重组。
当有必要强制计算顺序时,可以使用一个CASE
结构(见第 9.17 节)。例如,在一个WHERE
子句中使用下面的方法尝试避免除零是不可靠的:
SELECT ... WHERE x > 0 AND y/x > 1.5;
但是这是安全的:
SELECT ... WHERE CASE WHEN x > 0 THEN y/x > 1.5 ELSE false END;
一个以这种风格使用的CASE
结构将使得优化尝试失败,因此只有必要时才这样做(在这个特别的例子中,最好通过写y > 1.5*x
来回避这个问题)。
不过,CASE
不是这类问题的万灵药。上述技术的一个限制是, 它无法阻止常量子表达式的提早计算。如第 38.7 节 中所述,当查询被规划而不是被执行时,被标记成 IMMUTABLE
的函数和操作符可以被计算。因此
SELECT CASE WHEN x > 0 THEN x ELSE 1/0 END FROM tab;
很可能会导致一次除零失败,因为规划器尝试简化常量子表达式。即便是 表中的每一行都有x > 0
(这样运行时永远不会进入到 ELSE
分支)也是这样。
这个其实就是执行计划优化的问题,和正常写代码的时候一样,这都是很很常见的问题(例如编译器优化)
从修改的行中返回数据
INSERT INTO users (firstname, lastname) VALUES ('Joe', 'Cool') RETURNING id;
就这样吧
名字 | 别名 | 描述 |
---|---|---|
bigint | int8 | 有符号的8字节整数 |
bigserial | serial8 | 自动增长的8字节整数 |
bit [ (n) ] | 定长位串 | |
bit varying [ (n) ] varbit [ (n) ] | 变长位串 | |
boolean | bool | 逻辑布尔值(真/假) |
box | 平面上的普通方框 | |
bytea | 二进制数据(“字节数组”) | |
character [ (n) ] | char [ (n) ] | 定长字符串 |
character varying [ (n) ] | varchar [ (n) ] | 变长字符串 |
cidr | IPv4或IPv6网络地址 | |
circle | 平面上的圆 | |
date | 日历日期(年、月、日) | |
double precision | float8 | 双精度浮点数(8字节) |
inet | IPv4或IPv6主机地址 | |
integer | int, int4 | 有符号4字节整数 |
interval [ fields ] [ (p) ] | 时间段 | |
json | 文本 JSON 数据 | |
jsonb | 二进制 JSON 数据,已分解 | |
line | 平面上的无限长的线 | |
lseg | 平面上的线段 | |
macaddr | MAC(Media Access Control)地址 | |
macaddr8 | MAC(Media Access Control)地址(EUI-64格式) | |
money | 货币数量 | |
numeric [ (p, s) ] | decimal [ (p, s) ] | 可选择精度的精确数字 |
path | 平面上的几何路径 | |
pg_lsn | PostgreSQL日志序列号 | |
point | 平面上的几何点 | |
polygon | 平面上的封闭几何路径 | |
real | float4 | 单精度浮点数(4字节) |
smallint | int2 | 有符号2字节整数 |
smallserial | serial2 | 自动增长的2字节整数 |
serial | serial4 | 自动增长的4字节整数 |
text | 变长字符串 | |
time [ (p) ] [ without time zone ] | 一天中的时间(无时区) | |
time [ (p) ] with time zone | timetz | 一天中的时间,包括时区 |
timestamp [ (p) ] [ without time zone ] | 日期和时间(无时区) | |
timestamp [ (p) ] with time zone | timestamptz | 日期和时间,包括时区 |
tsquery | 文本搜索查询 | |
tsvector | 文本搜索文档 | |
txid_snapshot | 用户级别事务ID快照 | |
uuid | 通用唯一标识码 | |
xml | XML数据 |