类型 | 描述 | 样例 | 向量量化执行 |
---|---|---|---|
ARRAY | 存储了非数组类型的一维度,一索引的相同类型元素的数组 | {"sky","road","car"} | 不支持 |
BIT | 二进制数字(位) | B'10010101' | 不支持 |
BOOL | 布尔值 | true | 支持 |
BYTES | 二进制字符 | b'\141\061\142\062\143\063' | 支持 |
COLLATE | COLLATE 功能使您可以根据特定于语言和国家/地区的规则(称为归类)对STRING值进行排序。 | 'a1b2c3' COLLATE en | 不支持 |
DATE | 日期 | DATE '2019-01-25' | 支持 |
DECIMAL | 精确的定点数 | 1.2345 | 部分支持 |
FLOAT | 64位浮点数 | 1.2345 | 支持 |
INET | IPv4或IPv6地址 | 192.168.0.1 | 不支持 |
INT | 带符号整数,最大64位 | 12345 | 支持 |
INTERVAL | 时间跨度/间隔 | INTERVAL '2h30m30s' | 不支持 |
JSONB | JSON (JavaScript Object Notation) | '{"first_name": "Lola", "last_name": "Dog", "location": "NYC", "online" : true, "friends" : 547}' | 不支持 |
SERIAL | 将整数类型与默认表达式组合在一起的伪类型 | 148591304110702593 | 不支持 |
STRING | Unicode字符串 | 'a1b2c3' | 支持 |
TIME | UTC时间 | TIME '01:23:45.123456' | 不支持 |
TIMESTAMP /TIMESTAMPTZ | UTC中的日期和时间对 | TIMESTAMP '2016-01-25 10:10:10' TIMESTAMPTZ '2016-01-25 10:10:10-05:00' | TIMESTAMP 支持 TIMESTAMPTZ 不支持 |
UUID | 128位十六进制值 | 7f9c24e8-3b12-4fef-91e0-56a2d5a246ec | 支持 |
使用以下方法进行显式类型转换:
<type> 'string literal'
,用于将值的字符串形式转换为该类型的值。例如: DATE '2008-12-21'
,INT '123'
, 或 BOOL 'true'
。
<value>::<data type>
或等效的更长格式 CAST(<value> AS <data type>)
,它将一个内置类型的任意表达式转换为另一种(也称为类型强制或“转换”)如:NOW()::DECIMAL
, VARIANCE(a+2)::INT
。
注意:要创建常量值,请考虑使用类型注释而不是强制类型转换,因为它可提供更可预测的结果。
不是SQL类型时,其他内置转换函数,例如from_ip()
,to_ip()
,可在STRING
和BYTES
值之间转换IP地址。
您可以在每种数据类型详情的支持的转换部分的找到对应类型的转换信息。
ARRAY
数据类型存储了非数组类型的一维的相同类型元素的数据。
ARRAY
数据类型对于确保与ORM和其他工具的兼容性很有用。但是,如果不考虑这种兼容性,则可以更灵活的使用规范化的表。
注意:数据库不支持嵌套数组,同时不支持在数组上创建数据库索引以及不支持按数组排序
数据类型ARRAY的值可以通过以下方式表示:
ARRAY
添加到任何非数组数据类型。ARRAY
的值大小是可变的,为确保性能最好<1MB。超过该阈值,写放大和其他考虑因素可能导致性能显着下降。
CREATE TABLE a (b STRING[]);
INSERT INTO a VALUES (ARRAY['sky', 'road', 'car']);
SELECT * FROM a;
+----------------------+
| b |
+----------------------+
| {"sky","road","car"} |
+----------------------+
(1 row)
ARRAY
来创建数组列CREATE TABLE c (d INT ARRAY);
INSERT INTO c VALUES (ARRAY[10,20,30]);
SELECT * FROM c;
+------------+
| d |
+------------+
| {10,20,30} |
+------------+
(1 row)
SELECT * FROM c;
+------------+
| d |
+------------+
| {10,20,30} |
+------------+
(1 row)
SELECT d[2] FROM c;
+------+
| d[2] |
+------+
| 20 |
+------+
(1 row)
使用array_append
函数
SELECT * FROM c;
+------------+
| d |
+------------+
| {10,20,30} |
+------------+
(1 row)
UPDATE c SET d = array_append(d, 40) WHERE d[3] = 30;
SELECT * FROM c;
+---------------+
| d |
+---------------+
| {10,20,30,40} |
+---------------+
(1 row)
SELECT * FROM c;
+---------------+
| d |
+---------------+
| {10,20,30,40} |
+---------------+
(1 row)
UPDATE c SET d = d || 50 WHERE d[4] = 40;
SELECT * FROM c;
+------------------+
| d |
+------------------+
| {10,20,30,40,50} |
+------------------+
(1 row)
当数组的数据类型支持转换时,支持在ARRAY
值之间进行转换。例如,可以将BOOL
数组强制转换为INT
数组,而不能将BOOL
数组强制转换为TIMESTAMP
数组:
SELECT ARRAY[true,false,true]::INT[];
array
+---------+
{1,0,1}
(1 row)
SELECT ARRAY[true,false,true]::TIMESTAMP[];
pq: invalid cast: bool[] -> TIMESTAMP[]
您可以将数组强制转换为STRING
值,以与 PostgreSQL 兼容:
SELECT ARRAY[1,NULL,3]::string;
array
+------------+
{1,NULL,3}
(1 row)
SELECT ARRAY[(1,'a b'),(2,'c"d')]::string;
array
+----------------------------------+
{"(1,\"a b\")","(2,\"c\"\"d\")"}
(1 row)
BIT
和VARBIT
数据类型存储BIT
数组。使用BIT
,长度是固定的;使用VARBIT
,长度可以可变。
名称BIT VARYING
是VARBIT
的别名
BIT
数组常量表示为字面量串。例如,B'100101'
表示6位的数组 。
BIT
值中的位数确定如下:
类型 | 逻辑大小 |
---|---|
BIT | 1 bit |
BIT(N) | N bits |
VARBIT | 没有最大值 |
VARBIT(N) | 最大值为N bits |
BIT
值的有效大小比其逻辑位数大一个有界的常数因子。在内部以64位为增量存储 位数组,外加一个额外的整数值来编码长度。
BIT
值的总大小可以任意大,但建议将值保持在1 MB以下以确保性能。超过该阈值,写放大和其他考虑因素可能导致性能显着下降。
通过添加方括号创建数组列
CREATE TABLE b (x BIT, y BIT(3), z VARBIT, w VARBIT(3));
SHOW COLUMNS FROM b;
column_name | data_type | is_nullable | column_default | generation_expression | indices | is_hidden
+-------------+-----------+-------------+----------------+-----------------------+-----------+-----------+
x | BIT | true | NULL | | {} | false
y | BIT(3) | true | NULL | | {} | false
z | VARBIT | true | NULL | | {} | false
w | VARBIT(3) | true | NULL | | {} | false
rowid | INT8 | false | unique_rowid() | | {primary} | true
(5 rows)
INSERT INTO b(x, y, z, w) VALUES (B'1', B'101', B'1', B'1');
SELECT * FROM b;
x | y | z | w
+---+-----+---+---+
1 | 101 | 1 | 1
对于BIT
类型,该值必须与指定大小完全匹配:
INSERT INTO b(x) VALUES (B'101');
pq: bit string length 3 does not match type BIT
INSERT INTO b(y) VALUES (B'10');
pq: bit string length 2 does not match type BIT(3)
对于VARBIT
类型,该值不得大于指定的最大大小:
INSERT INTO b(w) VALUES (B'1010');
pq: bit string length 4 too large for type VARBIT(3)
BIT
值可以强制转换为以下任何数据类型:
类型 | 细节 |
---|---|
INT | 将位数组转换为相应的数值,将这些位解释为该值是使用二进制补码编码的。如果位数组大于整数类型,则将忽略左侧多余的位。例如,B'1010':: INT 等于10。 |
STRING | 将二进制数字打印为字符串。这将恢复文字表示形式。例如,B'1010':: STRING 等于'1010' 。 |
BOOL
数据类型存储布尔值false
或true
。
BOOLEAN
是BOOL
的别名。
BOOL
有两个预定义的命名常量:TRUE
和FALSE
(名称不区分大小写)
或者,可以通过强制数值来获得布尔值:将零强制为FALSE
,任何非零值为TRUE
。
CAST(0 AS BOOL)
(false)CAST(123 AS BOOL)
(true)BOOL
值的宽度为1个字节,但由于Hubble库元数据的因素,总存储大小可能会更大。
CREATE TABLE bool (a INT PRIMARY KEY, b BOOL, c BOOLEAN);
SHOW COLUMNS FROM bool;
column_name | data_type | is_nullable | column_default | generation_expression | indices | is_hidden
+-------------+-----------+-------------+----------------+-----------------------+-----------+-----------+
a | INT8 | false | NULL | | {primary} | false
b | BOOL | true | NULL | | {} | false
c | BOOL | true | NULL | | {} | false
(3 rows)
INSERT INTO bool VALUES (12345, true, CAST(0 AS BOOL));
SELECT * FROM bool;
+-------+------+-------+
a | b | c
+-------+------+-------+
12345 | true | false
(1 row)
BOOL
值可以强制转换为以下任何数据类型:
类型 | 细节 |
---|---|
INT | 将true 转换为1 ,将false 转换为0 |
DECIMAL | 将true 转换为1 ,将false 转换为0 |
FLOAT | 将true 转换为1 ,将false 转换为0 |
STRING | -- |
BYTES
数据类型存储可变长度的二进制字符串。
BYTEA
和BLOB
是BYTES
的别名。
以下三个是相同字节数组的等效文字:b'abc'
,b'\141 \142 \143'
,b'\x61 \x62 \x63'
。
除此语法外,还支持使用字符串文字,包括在上下文中的'...'
,e'...'
和x'....'
。
BYTES
值的大小是可变的,但建议将值保持在1 MB以下以确保性能。超过该阈值,写放大和其他考虑因素可能导致性能显着下降。
CREATE TABLE bytes (a INT PRIMARY KEY, b BYTES);
-- explicitly typed BYTES literals
INSERT INTO bytes VALUES (1, b'\141\142\143'), (2, b'\x61\x62\x63'), (3, b'\141\x62\c');
-- string literal implicitly typed as BYTES
INSERT INTO bytes VALUES (4, 'abc');
SELECT * FROM bytes;
+---+-----+
| a | b |
+---+-----+
| 1 | abc |
| 2 | abc |
| 3 | abc |
| 4 | abc |
+---+-----+
(4 rows)
可以将BYTES
值显式转换为STRING
。此转换总是成功。
支持两种转换模式,由会话变量bytea_output
控制:
hex
(默认):转换的输出以两个字符\
,x
开头,字符串的其余部分由输入中每个字节的十六进制编码组成。例如,x'48AA'::STRING
产生'H\xaa'
。escape
:转换的输出包含输入中的每个字节,如果是ASCII字符则保持原样,否则使用八进制转义格式\NNN
进行编码。例如,x'48AA'::STRING
产生'H\xaa'
。可以将STRING
值显式转换为BYTES
。如果十六进制数字无效或十六进制数字为奇数,则此转换将失败。支持两种转换模式:
\
和x
开头(例如\xAABB
),则字符串的其余部分将被解释为十六进制数字序列。然后将字符串转换为字节数组,其中每对十六进制数字都转换为一个字节。STRING
与BYTES
尽管在许多情况下,STRING
和BYTES
似乎都具有相似的行为,但在将它们转换为另一种之前,应先了解它们的细微差别。
STRING
将其所有数据视为字符,或更具体地说,将其视为Unicode代码点。 BYTES
将其所有数据视为字节字符串。在实现上的这种差异可能导致行为发生显着不同。例如,让我们采用一个复杂的Unicode字符,例如 ☃
(雪人表情符号):
SELECT length('☃'::string);
length
+--------+
1
SELECT length('☃'::bytes);
length
+--------+
3
在这种情况下,LENGTH(string)
测量字符串中存在的Unicode代码点的数量,而LENGTH(bytes)
测量存储该值所需的字节数。每个字符(或Unicode代码点)可以使用多个字节进行编码,因此两者之间的输出差异。
将文字转换为STRING
与BYTES
过SQL客户端输入的文字将根据类型转换为其他值:
BYTES
在开头对\x
赋予特殊含义,并通过将十六进制数字对替换为单个字节来转换其余部分。例如,\xff
等效于值为255的单个字节。STRING
没有给\x
赋予特殊含义,因此所有字符都被视为不同的Unicode代码点。例如,\xff
被视为长度为4(\
,x
,f
,和f
)的STRING
。COLLATE
功能使您可以根据特定的语言和国家地区的规则(称为排序规则)对STRING
值进行排序。
排序后的字符串很重要,因为不同的语言对于字母顺序(尤其是重音字母)有不同的规则。例如,在德语中,重音字母与非重音字母一起排序,而在瑞典语中,带重音字母则放在字母的末尾。排序规则是用于排序的一组规则,通常对应于一种语言,尽管某些语言具有多个排序不同的排序规则;例如,葡萄牙语对巴西和欧洲方言分别使用排序规则(分别为pt-BR
和pt-PT
)。
对整理字符串进行的操作,不能涉及排序规则不同的字符串或不具有排序规则的字符串。但是,可以动态添加或覆盖排序规则。
仅在需要按特定排序规则对字符串排序时才使用排序规则功能。我们之所以建议这样做,是因为每次构造或加载排序后的字符串到内存中时,数据库都会计算排序键,其大小与排序后的字符串的长度呈线性关系,此过程还需要额外的资源。
排序后的字符串可能比相应的未排序后的字符串大得多,具体取决于语言和字符串内容。例如,包含字符é
的字符串在法语语言环境中比在中文语言中产生更大的排序键。
与未排序的字符串相比,为排序后字符串创建索引需要更多的磁盘空间。如果是索引排序后字符串,则除了要存储排序后的字符串之外,还必须存储排序键。
支持Go语言包提供的排序规则。 <collation>
参数是每行末尾的BCP47语言标记,紧跟前面的//
。例如,支持南非荷兰语作为AF
进行排序
归类的字符串在SQL中用作常规字符串,但在其后附加了COLLATE
子句。
STRING COLLATE <collation>
。例如:CREATE TABLE foo (a STRING COLLATE en PRIMARY KEY);
-- Note: STRING 可用任意别名
<STRING value> COLLATE <collation>
。例如:INSERT INTO foo VALUES ('dog' COLLATE en);
您可以在STRING
列中为所有值设置默认排序规则。
CREATE TABLE de_names (name STRING COLLATE de PRIMARY KEY);
将值插入此列时,必须为每个值指定排序规则:
INSERT INTO de_names VALUES ('Backhaus' COLLATE de), ('Bär' COLLATE de), ('Baz' COLLATE de);
排序现在将按照de
处理,在字母排序中将ä视为 a :
SELECT * FROM de_names ORDER BY name;
name
+----------+
Backhaus
Bär
Baz
(3 rows)
您可以使用特定的排序规则而不是默认排序规则对列进行排序。
例如,如果您按德语(de
)和瑞典语(sv
)排序结果,则会收到不同的结果:
SELECT * FROM de_names ORDER BY name COLLATE sv;
name
+----------+
Backhaus
Baz
Bär
(3 rows)
您可以随时将任何字符串转换为排序规则。
SELECT 'A' COLLATE de < 'Ä' COLLATE de;
?column?
+----------+
true
(1 row)
但是,您不能比较具有不同归类的值:
SELECT 'Ä' COLLATE sv < 'Ä' COLLATE de;
pq: unsupported comparison operator: <collatedstring{sv}> < <collatedstring{de}>
您还可以使用强制转换从值中删除排序规则。
SELECT CAST(name AS STRING) FROM de_names ORDER BY name;
name
+----------+
Backhaus
Baz
Bär
(3 rows)
您可以使用pg_collation_for
内置函数或其替代语法形式COLLATION FOR
来返回整理后的字符串的语言环境名称。
SELECT pg_collation_for('Bär' COLLATE de);
pg_collation_for
+------------------+
"de"
(1 row)
这等效于:
SELECT COLLATION FOR ('Bär' COLLATE de);
pg_collation_for
+------------------+
"de"
(1 row)
该DATE
数据类型储存年月日信息。
DATE
类型的常量值可以使用解释后的文字或用DATE
类型注释或强制为DATE
类型的字符串文字表示。
日期的字符串格式为YYYY-MM-DD
。例如:DATE'2016-12-23'
。
支持在预期DATE
值的上下文中使用未解释的字符串文本。
DATE
列支持最大宽度为16个字节的值,但是由于数据库元数据因素,总存储大小可能会更大。
CREATE TABLE dates (a DATE PRIMARY KEY, b INT);
SHOW COLUMNS FROM dates;
column_name | data_type | is_nullable | column_default | generation_expression | indices | is_hidden
+-------------+-----------+-------------+----------------+-----------------------+-----------+-----------+
a | DATE | false | NULL | | {primary} | false
b | INT8 | true | NULL | | {} | false
(2 rows)
显式写入DATE
文字:
INSERT INTO dates VALUES (DATE '2016-03-26', 12345);
隐式写入DATE
文字:
INSERT INTO dates VALUES ('2016-03-27', 12345);
SELECT * FROM dates;
+------------+-------+
a | b
+------------+-------+
2016-03-26 | 12345
2016-03-27 | 12345
+------------+-------+
(2 rows)
DATE
值可以强制转换为以下任何数据类型:
类型 | 细节 |
---|---|
DECIMAL | 转换为Unix纪元(1970年1月1日)以来的天数 |
FLOAT | 转换为Unix纪元(1970年1月1日)以来的天数 |
TIMESTAMP | 将结果时间戳记中的时间设置为 00:00:00(午夜)。 |
INT | 转换为Unix纪元(1970年1月1日)以来的天数 |
STRING | -- |
DECIMAL
数据类型存储精确的小数。当保留精确的精度很重要时可以使用此类型,例如,使用货币数据。
DEC
和NUMRIC
是DECIMAL
的别名
使用DECIMAL(precision,scale)
限制DECIMAL
列,其中precision
是小数点左边和右边的最大位数,而scale
是小数点右边的精确位数。precision
不能小于scale
。使用DECIMAL(precision)
等效于DECIMAL(precision,0)
。
插入十进制值时:
scale
,则将四舍五入到scale
。scale
,则填充0直到scale
。precision
,则会报误。precision
和scale
相同,则插入的值必须四舍五入到小于1。可以将DECIMAL
类型的常量值输入为数字文字。例如:1.414
或-1234
。
无法使用数字文字直接输入正无穷大,负无穷大和NaN(Not-a-Number)的特殊IEEE754值,必须使用解释后的文字或字符串文字的显式转换来进行转换。
可以识别以下值:
语法 | 值 |
---|---|
inf , infinity , +inf , +infinity | +∞ |
-inf , -infinity | -∞ |
nan | (Not-a-Number) |
举例 :
DECIMAL '+Inf'
'-Inf'::DECIMAL
CAST('NaN' AS DECIMAL)
DECIMAL
值的大小是可变的,从9个字节开始。建议将值保持在64 KB以下,以确保性能。超过该阈值,写放大和其他因素可能导致性能显着下降。
CREATE TABLE decimals (a DECIMAL PRIMARY KEY, b DECIMAL(10,5), c NUMERIC);
SHOW COLUMNS FROM decimals;
column_name | data_type | is_nullable | column_default | generation_expression | indices | is_hidden
+-------------+---------------+-------------+----------------+-----------------------+-----------+-----------+
a | DECIMAL | false | NULL | | {primary} | false
b | DECIMAL(10,5) | true | NULL | | {} | false
c | DECIMAL | true | NULL | | {} | false
(3 rows)
INSERT INTO decimals VALUES (1.01234567890123456789, 1.01234567890123456789, 1.01234567890123456789);
SELECT * FROM decimals;
a | b | c
+------------------------+---------+------------------------+
1.01234567890123456789 | 1.01235 | 1.01234567890123456789
(1 rows)
# The value in "a" matches what was inserted exactly.
# The value in "b" has been rounded to the column's scale.
# The value in "c" is handled like "a" because NUMERIC is an alias.
DECIMAL
值可以强制转换为以下任何数据类型:
类型 | 细节 |
---|---|
BOOL | 0转换为false ;所有其他值都转换为true |
FLOAT | 丢失精度,如果值的太大,则可能会四舍五入到+/-无穷大;如果值的大小,则可能会四舍五入到+/- 0 |
INT | 截断小数的精度 |
STRING | -- |
支持各种不精确的浮点数数据类型,最高可达17位小数精度。它们在内部使用标准的双精度(64位二进制编码)IEEE754格式进行处理。
Name | Aliases |
---|---|
FLOAT | None |
REAL | FLOAT4 |
DOUBLE PRECISION | FLOAT8 |
数值文本可以作为浮点类型的输入。例如:1.414
或-1234
。
无法使用数字文字直接输入正无穷大,负无穷大和NaN(Not-a-Number)的特殊IEEE754值,必须使用解释后的文字或字符串文字的显式转换来进行转换。
可以识别以下值:
语法 | 值 |
---|---|
inf , infinity , +inf , +infinity | +∞ |
-inf , -infinity | -∞ |
nan | (Not-a-Number) |
举例 :
DECIMAL '+Inf'
'-Inf'::DECIMAL
CAST('NaN' AS DECIMAL)
FLOAT
列最多支持8个字节的值,由于库元数据因素,总存储大小可能会更大。
CREATE TABLE floats (a FLOAT PRIMARY KEY, b REAL, c DOUBLE PRECISION);
SHOW COLUMNS FROM floats;
column_name | data_type | is_nullable | column_default | generation_expression | indices | is_hidden
+-------------+-----------+-------------+----------------+-----------------------+-----------+-----------+
a | FLOAT8 | false | NULL | | {primary} | false
b | FLOAT4 | true | NULL | | {} | false
c | FLOAT8 | true | NULL | | {} | false
(3 rows)
INSERT INTO floats VALUES (1.012345678901, 2.01234567890123456789, CAST('+Inf' AS FLOAT));
SELECT * FROM floats;
a | b | c
+----------------+-----------+----------+
1.012345678901 | 2.0123458 | Infinity
(1 row)
# Note that the value in "b" has been limited to 7 digits.
FLOAT
值可以强制转换为以下任何数据类型:
类型 | 细节 |
---|---|
BOOL | 0转换为false ;所有其他值都转换为true |
DECIMAL | 如果值为NaN或+/- Inf,则会报告错误。 |
INT | 截断小数精度,并要求值介于-2 ^ 63和2 ^ 63-1之间 |
STRING | -- |
INET
数据类型存储IPv4或IPv6地址。
INET
类型的常量值可以使用解释的文字或用INET
类型注释或强制为INET
类型的字符串文字表示。
INET
常数可以使用以下格式表示:
格式 | 描述 |
---|---|
IPv4 | 标准RFC791规定的4个八位位组的格式,分别用十进制数表示,并用句点分隔。地址之后可选择性添加子网掩码。Examples: '190.0.0.0' , '190.0.0.0/24' |
IPv6 | 标准RFC8200指定的格式的8个冒号分隔的4个十六进制数字组。 IPv6地址可以映射到IPv4地址。地址之后可选择性添加子网掩码。Examples: '2001:4f8:3:ba:2e0:81ff:fe22:d1f1' , '2001:4f8:3:ba:2e0:81ff:fe22:d1f1/120' , '::ffff:192.168.0.1/24' |
举例 :
INET '192.168.0.1'
'192.168.0.1'
数据插入表时,数据类型隐式转换为 INET
注意: IPv4地址将在IPv6地址(包括IPv4映射的IPv6地址)之前排序
使用INET
值存储IPv4占用32位,存储IPv6占用128位。
CREATE TABLE computers (
ip INET PRIMARY KEY,
user_email STRING,
registration_date DATE
);
SHOW COLUMNS FROM computers;
column_name | data_type | is_nullable | column_default | generation_expression | indices | is_hidden
+-------------------+-----------+-------------+----------------+-----------------------+-----------+-----------+
ip | INET | false | NULL | | {primary} | false
user_email | STRING | true | NULL | | {} | false
registration_date | DATE | true | NULL | | {} | false
(3 rows)
INSERT INTO computers
VALUES
('192.168.0.1', 'info@google.com', '2018-01-31'),
('192.168.0.2/10', 'lauren@google.com', '2018-01-31'),
('2001:4f8:3:ba:2e0:81ff:fe22:d1f1/120', 'test@google.com', '2018-01-31');
SELECT * FROM computers;
ip | user_email | registration_date
+--------------------------------------+-------------------+-------------------+
192.168.0.2/10 | lauren@google.com | 2018-01-31
192.168.0.1 | info@google.com | 2018-01-31
2001:4f8:3:ba:2e0:81ff:fe22:d1f1/120 | test@google.com | 2018-01-31
(3 rows)
INET
值可以强制转换为以下数据类型:
STRING
-转换为'Address/subnet'
格式。支持各种有符号整数数据类型。
名称 | 允许的宽度 | 别名 | 范围 |
---|---|---|---|
INT | 64-bit | INTEGER INT8 INT64 BIGINT | -9223372036854775807 到 +9223372036854775807 |
INT2 | 16-bit | SMALLINT | -32768 到 +32767 |
INT4 | 32-bit | None | -2147483648 到 +2147483647 |
INT8 | 64-bit | INT | -9223372036854775807 到 +9223372036854775807 |
数值文本可以作为INT
类型的输入。例如:42
, -1234
或0xCAFE
不同的整数类型对允许值的范围设置了不同的约束,但是无论类型如何,所有整数都以相同的方式存储。较小的值比较大的值占用更少的空间(基于数值,而不是数据类型)。
默认情况下,INT
是INT8
的别名,它将创建64位带符号整数。这与Postgres的INT
默认值(32位默认值)不同,如果未将其编写为处理64位整数,无论是编写应用程序的语言,还是生成SQL时使用的ORM框架,则都可能会给应用程序带来问题。
例如,JavaScript语言运行时将数字表示为64位浮点小数,这意味着JS运行时只能表示53位的数字精度,因此最大合理值为2的53次或9007199254740992。这意味着默认INT
的最大值远远大于JavaScript可以表示为整数的值。在视觉上,大小差异如下:
9223372036854775807 # INT default max value
9007199254740991 # JS integer max value
鉴于上述情况,如果表包含具有默认大小的INT
值的列,并且您正在从中读取或通过JavaScript对其进行写入,则将无法正确地将值读取和写入该列。如果您使用的是自动生成前端和后端代码的框架(例如twirp),则可能会突然弹出此问题。后端代码可以处理64位带符号的整数,但是生成的客户端或是前端代码则不能。
如果您的应用程序要使用与默认值不同的整数大小,则可以更改以下一项或两项设置。例如,可以将以下任意一项设置为4
,以使INT
和SERIAL
成为32位整数INT4
和SERIAL4
的别名。
default_int_size
会话变量。 sql.defaults.default_int_size
群集设置。提示 : 如果您的应用程序需要精度数字,请使用DECIMAL数据类型。
CREATE TABLE ints (a INT PRIMARY KEY, b SMALLINT);
SHOW COLUMNS FROM ints;
column_name | data_type | is_nullable | column_default | generation_expression | indices | is_hidden
+-------------+-----------+-------------+----------------+-----------------------+-----------+-----------+
a | INT8 | false | NULL | | {primary} | false
b | INT2 | true | NULL | | {} | false
(2 rows)
INSERT INTO ints VALUES (1, 32);
SELECT * FROM ints;
a | b
+---+----+
1 | 32
(1 row)
INT
值可以强制转换为以下数据类型:
Type | Details |
---|---|
DECIMAL | –– |
FLOAT | 如果INT 值的大小大于2 ^ 53,则会失去精度。 |
BOOL | 0转换为false;所有其他值都将转换为true。 |
DATE | 转换为与Unix时间(1970年1月1日)间隔转换值的日期,转换值不可为负数 |
TIMESTAMP | 转换为与Unix时间(1970年1月1日)间隔转换值的时间戳, 时间戳记中的时间设置为00:00:00(午夜),转换值不可为负数 |
INTERVAL | 转换为秒。 |
STRING | –– |
INTERVAL
数据类型存储一个表示时间跨度的值。
INTERVAL(6)
注意 : 支持INTERVAL(6)作为别名仅出于兼容性目的。此别名不能确定INTERVAL值的大小。
INTERVAL
类型的常量值可以使用解释后的文字或用INTERVAL
类型注解的字符串或强制为INTERVAL
类型的字符串文字来表示。
INTERVAL
常数可以使用以下格式表示:
格式 | 描述 |
---|---|
标准SQL | INTERVAL 'Y-M D H:M:S' Y-M D : 使用单个值仅定义天数;使用两个值定义年份和月份。值必须是整数。 H:M:S : 使用单个值仅定义秒;使用两个值定义小时和分钟。值可以是整数或浮点数。 |
ISO 8601 | INTERVAL 'P1Y2M3DT4H5M6S' |
传统PostgreSQL | INTERVAL '1 year 2 months 3 days 4 hours 5 minutes 6 seconds' |
简略PostgreSQL | INTERVAL '1 yr 2 mons 3 d 4 hrs 5 mins 6 secs' |
支持在INTERVAL
值的上下文中使用未解释的字符串文本。
INTERVAL
列最多支持宽度为24个字节的值,但是由于元数据因素,总存储大小可能会更大。
间隔在内部存储为月,日和微秒。
CREATE TABLE intervals (a INT PRIMARY KEY, b INTERVAL);
SHOW COLUMNS FROM intervals;
column_name | data_type | is_nullable | column_default | generation_expression | indices | is_hidden
+-------------+-----------+-------------+----------------+-----------------------+-----------+-----------+
a | INT8 | false | NULL | | {primary} | false
b | INTERVAL | true | NULL | | {} | false
(2 rows)
INSERT INTO
intervals
VALUES (1, INTERVAL '1 year 2 months 3 days 4 hours 5 minutes 6 seconds'),
(2, INTERVAL '1-2 3 4:5:6'),
(3, '1-2 3 4:5:6');
SELECT * FROM intervals;
a | b
+---+-------------------------------+
1 | 1 year 2 mons 3 days 04:05:06
2 | 1 year 2 mons 3 days 04:05:06
3 | 1 year 2 mons 3 days 04:05:06
(3 rows)
INTERVAL
值可以强制转换为以下数据类型:
Type | Details |
---|---|
INT | 转换为秒数(秒精度) |
DECIMAL | 换为秒数(微秒精度) |
FLOAT | 转换为皮秒数 |
STRING | 转换为如 '1 year 2 mons 3 days 04:05:06' 的格式 |
TIME | 转换为HH:MM:SS ,该时间等于午夜后的时间间隔 |
JSONB
数据类型将JSON数据存储为JSONB
值的二进制存储,从而消除了空格,重复键和键顺序。 JSONB
支持倒排索引。
JSON
是 JSONB
的别名。
注意 : 在PostgreSQL中,
JSONB
和JSON
是两种不同的数据类型。这里的JSONB
/JSON
数据类型与PostgreSQL中的JSONB
数据类型相似。
JSONB
值上使用。 JSONB
列上创建标准索引,必须使用倒排索引。JSONB
数据类型的语法遵循RFC8259中指定的格式。 JSONB
类型的常量值可以使用解释后的文字或带JSONB
类型的字符串文字来表示。
JSONB
值有六种类型:
null
Boolean
String
Number
(如:decimal
, 非标准 int64
)
Array
(如:有序的JSONB
序列)
Object
(如:从字符串到JSONB
值的映射)
样例:
'{"type": "account creation", "username": "hubble123"}'
'{"first_name": "Zhang", "status": "Looking for treats", "location" : "Beijing"}'
注意:如果输入中包含重复的键,则仅保留最后一个值。
JSONB
值的大小是可变的,但建议将值保持在1MB以下以确保性能。超过该阈值,写放大和其他考虑因素可能导致性能显着下降。
JSONB
函数Function | Description |
---|---|
jsonb_array_elements() | 将JSONB 数组扩展为一组JSONB 值。 |
jsonb_build_object(...) | 从可变参数列表中构建一个JSONB 对象,该参数列表在键和值之间交替。 |
jsonb_each() | 将最外面的JSONB 对象扩展为一组键值对。 |
jsonb_object_keys() | 返回最外面的JSONB 对象中的有序键集合。 |
jsonb_pretty() | 返回给定的JSONB 值作为缩进的STRING 。请参见下面的示例。 |
有关受支持的JSONB
函数的完整列表 。
JSONB
操作符Operator | Description | Example |
---|---|---|
-> | 访问JSONB 字段,返回JSONB 值 | SELECT '[{"foo":"bar"}]'::JSONB->0->'foo' = '"bar"'::JSONB; |
->> | 访问JSONB 字段, 返回字符串 | SELECT '{"foo":"bar"}'::JSONB->>'foo' = 'bar'::STRING; |
@> | 测试左侧的JSONB 字段是否包含右侧的的JSONB 字段。 | SELECT ('{"foo": {"baz": 3}, "bar": 2}'::JSONB @> '{"foo": {"baz":3}}'::JSONB ) = true; |
有关受支持的JSONB
函数的完整列表 。
JSONB
列的表CREATE TABLE users (
profile_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
last_updated TIMESTAMP DEFAULT now(),
user_profile JSONB
);
SHOW COLUMNS FROM users;
column_name | data_type | is_nullable | column_default | generation_expression | indices | is_hidden
+--------------+-----------+-------------+-------------------+-----------------------+-----------+-----------+
profile_id | UUID | false | gen_random_uuid() | | {primary} | false
last_updated | TIMESTAMP | true | now():::TIMESTAMP | | {} | false
user_profile | JSONB | true | NULL | | {} | false
(3 rows)
INSERT INTO users (user_profile) VALUES
('{"first_name": "Zhang", "last_name": "San", "location": "Beijing", "online" : true, "friends" : 520}'),
('{"first_name": "Wang", "status": "Looking for treats", "location" : "ShangHai"}');
SELECT * FROM users;
profile_id | last_updated | user_profile
+--------------------------------------+---------------------------------+----------------------------------------------------------------------------------------------------+
8322a77e-84e3-4855-8a7a-f5a4adf5c6da | 2019-03-25 06:27:05.95072+00:00 | {"first_name": "Zhang", "friends": 520, "last_name": "San", "location": "Beijing", "online": true}
e6af0808-f4b3-4c6d-813b-f59553673711 | 2019-03-25 06:27:05.95072+00:00 | {"first_name": "Wang", "location": "ShangHai", "status": "Looking for treats"}
(2 rows)
要使用易于阅读的格式检索JSONB
数据,请使用jsonb_pretty()
函数。例如,从您在第一个示例中创建的表中检索数据:
SELECT profile_id, last_updated, jsonb_pretty(user_profile) FROM users;
profile_id | last_updated | jsonb_pretty
+--------------------------------------+----------------------------------+------------------------------------+
1740d746-2b14-41f7-b733-99c64de2de8b | 2020-03-25 06:48:51.240539+00:00 | {
| | "first_name": "Zhang",
| | "friends": 520,
| | "last_name": "San",
| | "location": "Beijing",
| | "online": true
| | }
47f6134b-7ae7-4078-9c55-811d12905c39 | 2020-03-25 06:48:51.240539+00:00 | {
| | "first_name": "Wang",
| | "location": "ShangHai",
| | "status": "Looking for treats"
| | }
(2 rows)
JSONB
值检索特定字段SELECT user_profile->'first_name' as first_name,user_profile->'location' as location FROM users;
first_name | location
+------------+------------+
"Zhang" | "Beijing"
"Wang" | "ShangHai"
(2 rows)
还可以使用 ->>
运算符将 JSONB
字段值作为STRING
值返回:
SELECT user_profile->>'first_name' as first_name,user_profile->>'location' as location FROM users;
first_name | location
+------------+------------+
Zhang | Beijing
Wang | ShangHai
(2 rows)
JSONB
列和计算列的表在此示例中,创建一个具有JSONB
列和计算列的表:
CREATE TABLE student_profiles (
id STRING PRIMARY KEY AS (profile->>'id') STORED,
profile JSONB
);
INSERT INTO student_profiles (profile) VALUES
('{"id": "d1001", "name": "Zhang San", "age": "15", "school": "RENDA", "sports": "none"}'),
('{"name": "Wang Wu", "age": "15", "id": "f3003", "school": "SIZHONG", "clubs": "Basketball"}'),
('{"name": "Li Si", "school" : "BAZHONG", "id": "t2002", "sports": "Track and Field", "clubs": "Chess"}');
SELECT * FROM student_profiles;
id | profile
+-------+------------------------------------------------------------------------------------------------------+
d1001 | {"age": "15", "id": "d1001", "name": "Zhang San", "school": "RENDA", "sports": "none"}
f3003 | {"age": "15", "clubs": "Basketball", "id": "f3003", "name": "Wang Wu", "school": "SIZHONG"}
t2002 | {"clubs": "Chess", "id": "t2002", "name": "Li Si", "school": "BAZHONG", "sports": "Track and Field"}
(3 rows)
主键id
作为profile
列中的字段进行计算。
JSONB
值可以转换为以下数据类型:
STRING
SERIAL
并非实际的数据类型,在定义一个表的列时,可以代替实际数据类型。它大约等效于使用带有DEFAULT表达式的整数类型,该整数类型在每次求值时都会生成不同的值。该默认表达式进而确保未指定此列的插入将收到自动生成的值,而不是NULL
。
注意 :提供
SERIAL
仅是为了与PostgreSQL兼容。应用程序应使用实际数据类型和合适的DEFAULT
表达式。大部分情况下,建议使用带有
gen_random_uuid()
函数的UUID
数据类型作为默认值,该值生成128位值(大于SERIAL的最大64位),并将它们更均匀地分散在表的所有基础键值范围内。当在索引或主键中使用UUID
列时,UUID
可以确保多个节点共担负载。
关键字SERIAL
在CREATE TABLE
时可以识别,并在创建表时自动转换为实际数据类型和DEFAULT
表达式。转换结果为数据库内部进行,并且可以使用SHOW CREATE
进行查看。
选择的DEFAULT
表达式可确保在行插入期间自动为列生成不同的值。这些值不能保证单调递增,有关详细信息,请参阅下面的文档。
SERIAL
有三种可能的翻译模式:
模式 | 描述 |
---|---|
rowid (默认) | SERIAL 表示默认为unique_rowid() 。实际数据类型始终为INT |
virtual_sequence | SERIAL 创建一个虚拟序列,表示DEFAULT nextval 。实际数据类型始终为INT 。 |
sql_sequence | SERIAL 创建常规SQL序列,表示DEFAULT nextval 。实际数据类型取决于SERIAL 变体。 |
rowid
和virtual_sequence
的生成值在rowid
和virtual_sequence
两种模式下,都会使用unique_rowid()
函数自动生成一个值。这将从执行INSERT
或UPSERT
操作的节点的当前时间戳和ID生成64位整数。从统计上讲,此操作在全球范围内可能是唯一的,除非是极端情况。
另外,由于使用unique_rowid()
生成的值不需要节点间的协调,因此当多个SQL客户端从不同节点向表写入数据时,它比下面讨论的其他模式sql_sequence
快得多。
sql_sequence
的生成值在这种模式下,在指定SERIAL
的表的同时,自动创建常规SQL序列。
实际数据类型确定如下:
SERIAL 变体 | 实际数据类型 |
---|---|
SERIAL2 , SMALLSERIAL | INT2 |
SERIAL4 | INT4 |
SERIAL | INT |
SERIAL8 , BIGSERIAL | INT8 |
每当使用插入或更新插入时都将使用nextval()
来递增序列并产生递增的值。
由于SQL序列将当前序列值保留在数据库中,因此当多个客户端通过不同节点同时使用序列时,需要进行节点间协调。这可能导致影响性能下降。
因此,应用程序应考虑使用unique_rowid()
或gen_random_uuid()
,尽可能不使用序列。
SERIAL
自动生成主键在此示例中,我们创建了一个以SERIAL
列作为主键的表,这样我们可以在插入时自动生成唯一的ID。
CREATE TABLE serial (a SERIAL PRIMARY KEY, b STRING, c BOOL);
SHOW COLUMNS
语句显示SERIAL
类型只是INT
的别名,默认值为unique_rowid()
。
SHOW COLUMNS FROM serial;
column_name | data_type | is_nullable | column_default | generation_expression | indices | is_hidden
+-------------+-----------+-------------+----------------+-----------------------+-----------+-----------+
a | INT8 | false | unique_rowid() | | {primary} | false
b | STRING | true | NULL | | {} | false
c | BOOL | true | NULL | | {} | false
(3 rows)
当我们在a
列中插入空值的行并显示新行时,我们看到每一行在a
列中都默认为唯一值。
INSERT INTO serial (b,c) VALUES ('red', true), ('yellow', false), ('pink', true);
INSERT INTO serial (a,b,c) VALUES (123, 'white', false);
SELECT * FROM serial;
a | b | c
+--------------------+--------+-------+
123 | white | false
540856466654756865 | red | true
540856466654789633 | yellow | false
540856466654822401 | pink | true
(4 rows)
常见的误解是PostgreSQL和MySQL中的自动递增类型会生成严格的顺序值。可能存在空白并且不能完全保证连续性:
要亲自体验一下,请在PostgreSQL中运行以下示例:
SERIAL
列的表: CREATE TABLE increment (a SERIAL PRIMARY KEY);
BEGIN; INSERT INTO increment DEFAULT VALUES; ROLLBACK;
BEGIN; INSERT INTO increment DEFAULT VALUES; COMMIT;
BEGIN; INSERT INTO increment DEFAULT VALUES; ROLLBACK;
BEGIN; INSERT INTO increment DEFAULT VALUES; COMMIT;
SELECT * from increment;
+---+
| a |
+---+
| 2 |
| 4 |
+---+
由于每个插入将a列中的序列加1,因此第一个提交的插入的值为2,第二个提交的插入的值为4。如您所见,这些值不是严格顺序的,最后一个值不能准确计算表中的行数。
总之,PostgreSQL和本数据库中的SERIAL
类型以及MySQL中的AUTO_INCREMENT
类型都表现一致,因为它们不创建严格的序列。与其他数据库相比,本数据库可能会产生更多的空白间隔,但生成这些值的速度会更快。
如果同时发生两个事务,则本数据库无法保证ID单调递增(即第一次提交小于第二次提交)。下面是三个演示此情况的方案:
案例1:
SERIAL
值x
。SERIAL
值y
。如果发生这种情况,尽管T1
和T2
开始和提交时间并不同,但本数据库无法保证x<y
还是x>y
。在这个特定示例中,甚至可能是因为差异小于10微秒导致x=y
,并且SERIAL
值是根据当前时间的微秒数构造的。
案例2:
SERIAL
值x
。 SERIAL
值y
。SERIAL
值y
。 如果发生这种情况,本数据库无法保证x<y
或x>y
。即使事务是同时开始和提交的,两者都可能发生。但是,明确的是x!=y
,因为这些值是在不同的节点上生成的。
案例3:
SERIAL
值x
。 SERIAL
值y
。 两个节点的系统时钟之间的差异小于250微秒。
如果发生这种情况,本数据库无法保证x<y
或x>y
。即使事务明显地发生在另一个之后,也可能在两个节点之间存在时钟偏差,并且第二个节点的系统时间设置得比第一个节点稍早。
STRING
数据类型存储一串Unicode字符。
STRING
的别名
CHARACTER
CHAR
VARCHAR
TEXT
STRING(N)
的别名:
CHARACTER(n)
CHARACTER VARYING(n)
CHAR(n)
CHAR VARYING(n)
VARCHAR(n)
使用 STRING(n)
来显示string
列的长度,其中n
是允许的最大Unicode代码点数(通常认为是字符)。
插入字符串时:
CAST('hello world'AS STRING(5))
),则将截断到限制长度。STRING(n)
及其所有别名。STRING
类型的值可以使用多种格式表示。
在SQL Shell中打印出STRING
值时,如果该值不包含特殊字符,则Shell使用简单的SQL字符串文字格式,否则使用转义格式。
STRING
值接受归类,使您可以根据特定于语言和国家/地区的规则对字符串进行排序。
注意:当前,您不能在索引或主键中使用排序规则的字符串;这样做会导致数据库崩溃。
STRING
值的大小是可变的,但建议将值保持在64KB以下以确保性能。超过该阈值,写放大和其他考虑因素可能导致性能显着下降。
CREATE TABLE strings (a STRING PRIMARY KEY, b STRING(4), c TEXT);
SHOW COLUMNS FROM strings;
column_name | data_type | is_nullable | column_default | generation_expression | indices | is_hidden
+-------------+-----------+-------------+----------------+-----------------------+-----------+-----------+
a | STRING | false | NULL | | {primary} | false
b | STRING(4) | true | NULL | | {} | false
c | STRING | true | NULL | | {} | false
(3 rows)
INSERT INTO strings VALUES ('a1b2c3d4', 'e5f6', 'g7h8i9');
SELECT * FROM strings;
a | b | c
+----------+------+--------+
a1b2c3d4 | e5f6 | g7h8i9
(1 row)
CREATE TABLE aliases (a STRING PRIMARY KEY, b VARCHAR, c CHAR);
SHOW COLUMNS FROM aliases;
column_name | data_type | is_nullable | column_default | generation_expression | indices | is_hidden
+-------------+-----------+-------------+----------------+-----------------------+-----------+-----------+
a | STRING | false | NULL | | {primary} | false
b | VARCHAR | true | NULL | | {} | false
c | CHAR | true | NULL | | {} | false
(3 rows)
INSERT INTO aliases VALUES ('abcd1234', 'ef56', 'g');
SELECT * FROM aliases;
a | b | c
+----------+------+---+
abcd1234 | ef56 | g
(1 row)
可以将STRING
值强制转换为以下任何数据类型:
类型 | 细节 |
---|---|
BOOL | 需要支持BOOL 字符串类型, 如: 'true'.. |
BYTES | 需要支持的BYTES 字符串格式,例如 b'\141\061\142\062\143\063' |
DATE | 需要支持DATE 字符串类型, 如: '2019-01-28'. |
DECIMAL | 需要支持DECIMAL 字符串类型, 如: '1.1'. |
FLOAT | 需要支持FLOAT 字符串类型, 如: '1.1'. |
INET | 需要支持INET 字符串类型, e.g, '192.168.0.1'. |
INT | 需要支持INT 字符串类型, 如: '10'. |
INTERVAL | 需要支持INTERVAL 字符串类型, 如: '1h2m3s'. |
TIME | 需要支持TIME 字符串类型, 如: '01:22:12' . |
TIMESTAMP | 需要支持TIMESTAMP 字符串类型, 如: '2019-01-28 10:10:10.222222'. |
STRING
与BYTES
尽管在许多情况下,STRING
和BYTES
似乎都具有相似的行为,但在将它们转换为另一种之前,应先了解它们的细微差别。
STRING
将其所有数据视为字符,或更具体地说,将其视为Unicode代码点。 BYTES
将其所有数据视为字节字符串。在实现上的这种差异可能导致行为发生显着不同。例如,让我们采用一个复杂的Unicode字符,例如(雪人表情符号):
SELECT length('☃'::string);
length
+--------+
1
SELECT length('☃'::bytes);
length
+--------+
3
在这种情况下,LENGTH(string)
测量字符串中存在的Unicode代码点的数量,而LENGTH(bytes)
测量存储该值所需的字节数。每个字符(或Unicode代码点)可以使用多个字节进行编码,因此两者之间输出存在差异。
将文字转换为STRING
与BYTES
通过SQL客户端输入的文字将根据类型转换为其他值:
BYTES
在开头对\x
赋予特殊含义,并通过将十六进制数字对替换为单个字节来转换其余部分。例如,\xff
等效于值为255的单个字节。STRING
没有给\x
赋予特殊含义,因此所有字符都被视为不同的Unicode代码点。例如,\xff
被视为长度为4(\
,x
,f
和f
)的STRING
。TIME
数据类型以UTC格式存储一天中的时间。
TIME WITHOUT TIME ZONE
TIME
类型的常量可以使用解释文本表示,或用使用TIME
类型注释的字符串文字或强制为TIME
类型来表示。
时间的字符串格式为HH:MM:SS.SSSSSS
。例如:TIME '08:30:30.000001'
。
如果没有歧义,则简单的未注释字符串文字也可以自动解释为TIME
类型。请注意,TIME
的小数部分是可选的,并且四舍五入到微秒(即小数点后六位)以与PostgreSQL协议兼容。
TIME
列最多支持8个字节的值,但是由于库元数据的因素,总存储大小可能会更大。
CREATE TABLE time (time_id INT PRIMARY KEY, time_val TIME);
SHOW COLUMNS FROM time;
column_name | data_type | is_nullable | column_default | generation_expression | indices | is_hidden
+-------------+-----------+-------------+----------------+-----------------------+-----------+-----------+
time_id | INT8 | false | NULL | | {primary} | false
time_val | TIME | true | NULL | | {} | false
(2 rows)
INSERT INTO time VALUES (1, TIME '08:40:00'), (2, TIME '08:41:40');
SELECT * FROM time;
time_id | time_val
+---------+----------+
1 | 08:40:00
2 | 08:41:40
(2 rows)
比较TIME
值:
SELECT (SELECT time_val FROM time WHERE time_id = 1) < (SELECT time_val FROM time WHERE time_id = 2);
?column?
+---------+
true
(1 row)
可以将TIME
值强制转换为以下任何数据类型:
类型 | 细节 |
---|---|
INTERVAL | 转换为从午夜(00:00)开始的时间范围 |
STRING | 转换为格式“ HH:MM:SS” |
TIMESTAMP
和TIMESTAMPTZ
数据类型以UTC格式存储日期和时间对。
TIMESTAMP
有两个变形:
TIMESTAMP
以UTC形式表示所有TIMESTAMP
值。TIMESTAMPTZ
将TIMESTAMP
值从UTC转换为客户端的会话时区(除非为该值指定另一个时区)。但是,从概念上讲,TIMESTAMPTZ
不存储任何时区数据。注意:默认会话时区为UTC,这意味着默认情况下
TIMESTAMPTZ
值以UTC显示。
这两个变形之间的区别在于,TIMESTAMPTZ
使用客户端的会话时区,而另一个根本不使用。这种情况扩展到类似TIMESTAMPTZ
值的函数,如now()
和extract()
。
我们建议始终使用TIMESTAMPTZ
变体,因为TIMESTAMP
有时会忽略会话偏移量时导致的意想不到的问题。但是我们建议您避免为数据库设置会话时间。
TIMESTAMP
, TIMESTAMP WITHOUT TIME ZONE
TIMESTAMPTZ
, TIMESTAMP WITH TIME ZONE
TIMESTAMP
/ TIMESTAMPTZ
类型的常量值可以使用解释文本表示,或用TIMESTAMP
/ TIMESTAMPTZ
类型注释字符串文字或强制为TIMESTAMP
/ TIMESTAMPTZ
类型来表示。
TIMESTAMP
常量可以使用以下字符串文字格式表示:
格式 | 示例 |
---|---|
Date only | TIMESTAMP '2016-01-25' |
Date and Time | TIMESTAMP '2016-01-25 10:10:10.555555' |
ISO 8601 | TIMESTAMP '2016-01-25T10:10:10.555555' |
要表示TIMESTAMPTZ
值(时区与UTC偏移),请使用以下格式:TIMESTAMPTZ '2019-02-25 10:10:10.555555-05:00'
如果明确,简单的未注释字符串文字也可以自动解释为TIMESTAMP
或TIMESTAMPTZ
类型。
请注意,小数部分是可选的,并且四舍五入到微秒(十进制后的6位数),以便与PostgreSQL协议兼容。
TIMESTAMP
/ TIMESTAMPTZ
列最多支持宽度为12个字节的值,但是由于元数据因素,总存储大小可能会更大。
CREATE TABLE timestamps (a INT PRIMARY KEY, b TIMESTAMPTZ);
SHOW COLUMNS FROM timestamps;
column_name | data_type | is_nullable | column_default | generation_expression | indices | is_hidden
+-------------+-------------+-------------+----------------+-----------------------+-----------+-----------+
a | INT8 | false | NULL | | {primary} | false
b | TIMESTAMPTZ | true | NULL | | {} | false
(2 rows)
INSERT INTO timestamps VALUES (1, TIMESTAMPTZ '2019-03-25 10:10:10'), (2, TIMESTAMPTZ '2019-03-25');
SELECT * FROM timestamps;
a | b
+---+-----------------------+
1 | 2019-03-25 10:10:10+08
2 | 2019-03-25 00:00:00+08
(2 rows)
可以将TIMESTAMP
值强制转换为以下任何数据类型:
类型 | 细节 |
---|---|
DECIMAL | 转换为Unix时间至今的秒数(1970年1月1日)。 |
FLOAT | 转换为Unix时间至今的秒数(1970年1月1日)。 |
TIME | 转换为时间戳的时间部分(HH:MM:SS) |
INT | 转换为Unix时间至今的秒数(1970年1月1日)。 |
DATE | -- |
STRING | -- |
UUID
(通用唯一标识符)数据类型存储一个128位的值,该值在空间和时间上都是唯一的。
建议:要自动生成唯一的行ID,建议将带有
gen_random_uuid()
函数的UUID
作为默认值。
UUID
值可以使用以下格式表示:
格式 | 描述 |
---|---|
标准RFC4122指定的格式 | 连字号分隔的8、4、4、4、12个十六进制数字的组。如: acde070d-8c4c-4f0d-9d8a-162843c10333 |
带括号 | 带括号的标准RFC4122指定格式。如: {acde070d-8c4c-4f0d-9d8a-162843c10333} |
作为 BYTES | 指定为字节的UUID 值。如: b'kafef00ddeadbeed' |
UUID 用作URN | UUID 可以用作统一资源名称(URN)。在这种情况下,格式指定为“ urn:uuid:”,后跟着标准RFC4122指定的格式。如: urn:uuid:63616665-6630-3064-6465-616462656564 |
一个UUID
值的宽度为128位,但是由于元数据因素,总存储大小可能会更大。
UUID
值的表使用标准RFC4122指定的格式创建具有UUID
的表
CREATE TABLE v (token uuid);
INSERT INTO v VALUES ('63616665-6630-3064-6465-616462656562');
SELECT * FROM v;
token
+--------------------------------------+
63616665-6630-3064-6465-616462656562
(1 row)
用大括号以标准RFC4122指定的格式创建具有UUID
的表
INSERT INTO v VALUES ('{63616665-6630-3064-6465-616462656563}');
SELECT * FROM v;
token
+--------------------------------------+
63616665-6630-3064-6465-616462656562
63616665-6630-3064-6465-616462656563
(2 rows)
用UUID
创建字节格式的表
INSERT INTO v VALUES (b'kafef00ddeadbeed');
SELECT * FROM v;
+--------------------------------------+
63616665-6630-3064-6465-616462656562
63616665-6630-3064-6465-616462656563
6b616665-6630-3064-6465-616462656564
(3 rows)
创建一个表并将UUID
用作URN
INSERT INTO v VALUES ('urn:uuid:63616665-6630-3064-6465-616462656564');
SELECT * FROM v;
token
+--------------------------------------+
63616665-6630-3064-6465-616462656562
63616665-6630-3064-6465-616462656563
6b616665-6630-3064-6465-616462656564
63616665-6630-3064-6465-616462656564
(4 rows)
要自动生成唯一的行ID,请使用带有gen_random_uuid()
函数的UUID
列作为默认值:
CREATE TABLE users (
id UUID NOT NULL DEFAULT gen_random_uuid(),
city STRING NOT NULL,
name STRING NULL,
address STRING NULL,
CONSTRAINT "primary" PRIMARY KEY (city ASC, id ASC),
FAMILY "primary" (id, city, name, address)
);
INSERT INTO users (name, city) VALUES ('Zhang', 'Beijing'), ('Wang', 'Shanghai'), ('Li', 'Beijing');
SELECT * FROM users;
id | city | name | address
+--------------------------------------+----------+-------+---------+
5a583e85-a1ce-45bc-a103-ff3490c365e2 | Beijing | Li | NULL
f61dec54-3fc6-489d-baef-de71bd6509b8 | Beijing | Zhang | NULL
f92c53f1-0992-47f8-9a95-b43d54895f6e | Shanghai | Wang | NULL
(3 rows)
或者,您可以将BYTES
列与uuid_v4()
函数一起用作默认值:
CREATE TABLE users2 (
id BYTES DEFAULT uuid_v4(),
city STRING NOT NULL,
name STRING NULL,
address STRING NULL,
CONSTRAINT "primary" PRIMARY KEY (city ASC, id ASC),
FAMILY "primary" (id, city, name, address)
);
INSERT INTO users2 (name, city) VALUES ('Zhao', 'Beijing'), ('Liu', 'Shanghai'), ('Chen', 'Beijing');
SELECT * FROM users2;
id | city | name | address
+------------------------------------------------------+----------+------+---------+
~T\021\015'\355G\315\251\270\317\020\304\002\020\345 | Beijing | Zhao | NULL
\354\3331\374\365\364J'\242\305-\000H\2514\011 | Beijing | Chen | NULL
,`?\233t\235O\361\201\037\353\021\370\321\335G | Shanghai | Liu | NULL
(3 rows)
无论哪种情况,生成的ID都是128位,基数足够大,几乎不可能生成重复值。同样,一旦表超出单个键值范围(默认情况下超过64MB),新的ID将散布在表的所有范围内,因此可能散布在不同的节点上。这意味着多个节点将分担负载。
这种方法的缺点是创建的主键在直接查询中可能没有用,这可能需要与另一个表或辅助索引联接。
如果将生成的ID存储在相同的键值范围内很重要,则可以显式地或通过SERIAL
类型将整数类型与unique_rowid()
函数用作默认值:
CREATE TABLE users3 (
id INT DEFAULT unique_rowid(),
city STRING NOT NULL,
name STRING NULL,
address STRING NULL,
CONSTRAINT "primary" PRIMARY KEY (city ASC, id ASC),
FAMILY "primary" (id, city, name, address)
);
INSERT INTO users3 (name, city) VALUES ('Zhang', 'Beijing'), ('Zhao', 'Shanghai'), ('Li', 'Beijing');
SELECT * FROM users3;
id | city | name | address
+--------------------+----------+-------+---------+
541068110770601985 | Beijing | Zhang | NULL
541068110770700289 | Beijing | Li | NULL
541068110770667521 | Shanghai | Zhao | NULL
(3 rows)
在插入或向上插入时,unique_rowid()
函数根据执行插入的节点的时间戳和ID生成默认值。这样的时间排序的值可能是全局唯一的,除非每个节点每秒生成大量ID(100,000+)。
可以将UUID
值强制转换为以下任何数据类型:
类型 | 细节 |
---|---|
BYTES | -- |