一 标识符和关键字
1. SQL
标识符和关键字必须以一个字母
(a-z
以及带变音符的字母和非拉丁字母
)
或下划线
(_)
开头,
随后的字符可以是字母、下划线、数字
(0-9)
、
美元符号
($)
。
2.
根据
SQL
标准,美元符号不允许出现在标识符中,
因此使用美元符号将不易移植。
3. SQL
标准不会定义包含数字或者以下划线开头或结尾的关键字,
因此按照这种格式定义的标识符是安全的,不会和将来标准的扩展特性冲突。
4.
系统使用不超过
NAMEDATALEN-1
个字符作为标识符;
你可以在命令中写更长的名字,但它们会被截断。
(1)NAMEDATALEN
的缺省值是
64
,
因此标识符最大长度是
63
字节。
(2)
如果觉得这个限制有问题,那么你可以在
src/include/pg_config_manual.h
里修改
NAMEDATALEN
来改变它。
5.
关键字和未被引号包围的标识符都是大小写无关的,但是建议:把关键字写成大写,而名字等用小写。
UPDATE MY_TABLE SET A = 5;
和
uPDaTE my_TabLE SeT a = 5;
是等效的。
6.
把一个标识符用引号包围起来同时也令它大小写相关,而没有引号包围起来的名字总是转成小写。
(1)
标识符
FOO
,
foo
和
"foo"
是等价的
PostgreSQL
名字
(2)
但
"Foo"
和
"FOO"
与上面三个以及它们之间都是不同的。
PostgreSQL
里对未加引号的名子总是转换成小写
(3)
这和
SQL
标准是不兼容的,
SQL
标准要求未用引号包围起来的名字总是转成大写。因此根据标准,
foo
等于
"FOO"
但不等于
"foo"
(4)
如果你想编写可移植的程序,那么我们建议你要么就总是用引号包围某个名字,要么就从来不引
二 常量
1.
两个只是通过至少一个换行符的空白分隔的字符串常量会被连接在一起,
并当做它们是写成一个常量处理。
(1)SELECT 'foo'
'bar';
和
SELECT 'foobar';
是等价的。
2.
转义字符串常量,这是一个
PostgreSQL
对
SQL
标准的扩展。转义字符串语法是通过在字符串前写字母
E (
大写或者小写
)
的方法声明的。
(1)C
风格的转义字符串常量。
=> select e'this is \n a string!';
?column?
------------
this is +
a string!
(1 row)
主意:最好是不使用反斜杠转义。如果你需要使用反斜杠转义来表示特殊的字符,
那么请在字符串常量前加上
E
。
要在字符串常量里包含反斜杠,
则写两个反斜杠
(\\)
。另外,
PostgreSQL
允许用一个反斜杠来转义单引号
\'
,
不过,将来版本
的
PostgreSQL
将不允许这么用。所以最好坚持使用符合标准的
''
。
(2)Unicode
转义字符串常量。一个转义
Unicode
字符常量以
U&
或者
u&
开始,在引号中,
通过写一个后面跟有
4
位
16
进制代码点或跟有“
+
”号和
6
位
16
进制代码点的反斜杠,
Unicode
字符可以写成转义格式。
例如:
U&'d\0061t\+000061';
和
U&'d!0061t!+000061' UESCAPE '!';
和
u&'d!0061t!0061' UESCAPE '!';
都是代表“
data
”
cd03=> select U&'d!0061t!+000061' UESCAPE '!';
?column?
----------
data
(1 row)
(3)
美元符引用字符串常量。如果一个字符串里面包含了很多特殊字符,如:
[\t\r\n\v\\]
,那么用
$q$[\t\r\n\v\\]$q$
这种方式表示会很方便(
$q$
,是一个字符串开始和结束标签,两个标签大小写一致)。
但是这并非
sql
标准。
=> select $q$[\t\r\n\v\\]$q$;
?column?
--------------
[\t\r\n\v\\]
(1 row)
在定义函数是经常用到,如:
$function$
BEGIN
RETURN ($1 ~ $q$[\t\r\n\v\\]$q$);END;
$function$
(4)
位串常量
,
位串常量里可以用的字符只有
0
和
1
。
2
进制:
=> SELECT B'1001';
?column?
----------
1001
(1 row)
16
进制:
=> SELECT X'1FF';
?column?
--------------
000111111111
(1 row)
三 数据类型
常用的数据类型:
名字 | 别名 | 描述 |
---|---|---|
bigint | int8 | 有符号8字节整数 |
bigserial | serial8 | 自增8字节整数 |
bit [ (n) ] | 定长位串 | |
bit varying [ (n) ] | varbit | 变长位串 |
boolean | bool | 逻辑布尔值(真/假) |
box | 平面上的矩形 | |
bytea | 二进制数据("字节数组") | |
character varying [ (n) ] | varchar [ (n) ] | 变长字符串 |
character [ (n) ] | char [ (n) ] | 定长字符串 |
cidr | IPv4 或 IPv6 网络地址 | |
circle | 平面上的圆 | |
date | 日历日期(年, 月, 日) | |
double precision | float8 | 双精度浮点数字(8字节) |
inet | IPv4 或 IPv6 主机地址 | |
integer | int, int4 | 有符号 4 字节整数 |
interval [ fields ] [ (p) ] | 时间间隔 | |
line | 平面上的无限长直线 | |
lseg | 平面上的线段 | |
macaddr | MAC (Media Access Control)地址 | |
money | 货币金额 | |
numeric [ (p, s) ] | decimal [ (p, s) ] | 可选精度的准确数字 |
path | 平面上的几何路径 | |
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 数据 | |
json | JSON 数据 |
1. 负数在计算机中以其正值的补码形式表达,能够表示多一个数字,而且避免了减法运算
smallint | 2 字节 | 小范围整数 | -32768 到 +32767 |
=> insert into jay_test values(32768);
ERROR: smallint out of range
ERROR: smallint out of range
数值类型
名字 | 存储空间 | 描述 | 范围 |
---|---|---|---|
smallint | 2 字节 | 小范围整数 | -32768 到 +32767 |
integer | 4 字节 | 常用的整数 | -2147483648 到 +2147483647 |
bigint | 8 字节 | 大范围整数 | -9223372036854775808 到 +9223372036854775807 |
decimal | 变长 | 用户声明精度,精确 | 小数点前 131072 位;小数点后 16383 位 |
numeric | 变长 | 用户声明精度,精确 | 小数点前 131072 位;小数点后 16383 位 |
real | 4 字节 | 变精度,不精确 | 6 位十进制数字精度 |
double precision | 8 字节 | 变精度,不精确 | 15 位十进制数字精度 |
smallserial | 2 字节 | 小范围自增整数 | 1 到 32767 |
serial | 4 字节 | 自增整数 | 1 到 2147483647 |
bigserial | 8 字节 | 大范围自增整数 | 1 到 9223372036854775807 |
2.如果要表示精确的小数,用decimal和numeric,两者都是一样的。
3.real和double precision都不能表示准确的小数。
(1)real只能保存6位数字,科学计数法也是一样(指数部分不算)
(2)如果整数位已经大于六位,则采用科学计数法:5.24961e+12
(3)如果小数位+整数位(整数位小于六位)大于六位,会四舍五入
(4)所以real结果是很难预料的,而且值采用科学计数法之后误差会变大
(5)如果使用real类型,应该确保值不会超过999999。
(6)但是效率会比decimal和numeric高!因为他的位数是固定的。
(7)取值范围:最大值的二进制表示为0/1(符合位) 11111111(指数位) 111 111 111 111 111 111 111 11(尾数位),即x=+/-(2-2^(-23)) * 2^127=+/-3.40282e+38
(8)特殊值
Infinity:正无穷
-Infinity:负无穷
NaN:不是一个数值
例如:
=> create table jay_test(id real);
CREATE TABLE
cd03=> insert into jay_test values(123.342453457345);
INSERT 0 1
cd03=> select * from jay_test ;
id
---------
123.342
(1 row)
4. numeric
类型
存储非常大的数字并且准确地进行计算,
用于货币金额和其它要求精确计算的场合
,
numeric类型上的算术运算比整数类型或者浮点数类型要慢很多。
NUMERIC(
precision
,
scale)
precision:精度 最大值为1000
scale:标度 如果传入的小数标度大于声明的标度,则四舍五入。
例如:2.234的精度为4,标度为3
numeric 类型的数据值在物理上是不带任何前导或者后缀零的形式存储的。 因此,字段上声明的精度和标度都是最大值,而不是固定分配的。在这个方面,
numeric
类型更类似于
varchar(n)
而不是
char(n)
。实际存储是每四个十进制位两个字节, 然后在整个数据上加上三到八个字节的额外开销。
numeric类型允许用特殊值NaN 表示"不是一个数字"。任何在NaN上面的操作都生成另外一个 NaN。PostgreSQL认为NaN相等, 并且大于所有非NaN值。
一个
serial
类型创建的序列在所属的字段被删除的时候自动删除。
注意:不管
smallserial
,
serial
还是
bigserial,生成的序列最大值总是9223372036854775807(bigint),但是实际字段可接受的值可能没有这么大,如:
smallserial可接受的最大值为:
32767,但是序列生成的值可能大于这个值,那么在插入的时候报错。
这三种类型之间没有性能差别,除了当使用填充空白类型时的增加存储空间, 和当存储长度约束的列时一些检查存入时长度的额外的CPU周期。 虽然在某些其它的数据库系统里,
character(n)
有一定的性能优势,但在
PostgreSQL
里没有。 事实上,
character(n)
通常是这三个中最慢的, 因为额外存储成本。在大多数情况下,应该使用
text
或
character varying
。
但是实际测试结果如下:
结论:1.插入1百万条记录,varchar稍快。
2.更新70万条记录,char明显更快。
3.在存储空间上,varchar明显比char更节约空间。
4.另外由于postgres才用mvcc(多版本并发控制),无论更新或者删除数据都会使表内容变大。
4.另外由于postgres才用mvcc(多版本并发控制),无论更新或者删除数据都会使表内容变大。