数据类型

支持的类型

类型描述样例向量量化执行
ARRAY存储了非数组类型的一维度,一索引的相同类型元素的数组{"sky","road","car"}不支持
BIT二进制数字(位)B'10010101'不支持
BOOL布尔值true支持
BYTES二进制字符b'\141\061\142\062\143\063'支持
COLLATECOLLATE功能使您可以根据特定于语言和国家/地区的规则(称为归类)对STRING值进行排序。'a1b2c3' COLLATE en不支持
DATE日期DATE '2019-01-25'支持
DECIMAL精确的定点数1.2345部分支持
FLOAT64位浮点数1.2345支持
INETIPv4或IPv6地址192.168.0.1不支持
INT带符号整数,最大64位12345支持
INTERVAL时间跨度/间隔INTERVAL '2h30m30s'不支持
JSONBJSON (JavaScript Object Notation)'{"first_name": "Lola", "last_name": "Dog", "location": "NYC", "online" : true, "friends" : 547}'不支持
SERIAL将整数类型与默认表达式组合在一起的伪类型148591304110702593不支持
STRINGUnicode字符串'a1b2c3'支持
TIMEUTC时间TIME '01:23:45.123456'不支持
TIMESTAMP/TIMESTAMPTZUTC中的日期和时间对TIMESTAMP '2016-01-25 10:10:10' TIMESTAMPTZ '2016-01-25 10:10:10-05:00'TIMESTAMP 支持 TIMESTAMPTZ 不支持
UUID128位十六进制值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(),可在STRINGBYTES值之间转换IP地址。

您可以在每种数据类型详情的支持的转换部分的找到对应类型的转换信息。


ARRAY

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)

使用append(||)运算符

> 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

BITVARBIT数据类型存储BIT数组。使用BIT,长度是固定的;使用VARBIT,长度可以可变。

别名

名称BIT VARYINGVARBIT的别名

语法

BIT数组常量表示为字面量串。例如,B'100101'表示6位的数组 。

大小

BIT值中的位数确定如下:

类型逻辑大小
BIT1 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

BOOL数据类型存储布尔值falsetrue

别名

BOOLEANBOOL的别名。

语法

BOOL有两个预定义的命名常量:TRUEFALSE(名称不区分大小写)

或者,可以通过强制数值来获得布尔值:将零强制为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值可以强制转换为以下任何数据类型:

类型细节
INTtrue转换为1,将false转换为0
DECIMALtrue转换为1,将false转换为0
FLOATtrue转换为1,将false转换为0
STRING--

BYTES

BYTES数据类型存储可变长度的二进制字符串。

别名

BYTEABLOBBYTES的别名。

语法

以下三个是相同字节数组的等效文字: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产生'\x48AA'
  • escape:转换的输出包含输入中的每个字节,如果是ASCII字符则保持原样,否则使用八进制转义格式\NNN进行编码。例如,x'48AA'::STRING产生'0\252'

可以将STRING值显式转换为BYTES。如果十六进制数字无效或十六进制数字为奇数,则此转换将失败。支持两种转换模式:

  • 如果字符串以两个特殊字符\x开头(例如\xAABB),则字符串的其余部分将被解释为十六进制数字序列。然后将字符串转换为字节数组,其中每对十六进制数字都转换为一个字节。
  • 否则,该字符串将转换为包含其UTF-8编码的字节数组。

STRING vs. BYTES

尽管在许多情况下,STRINGBYTES似乎都具有相似的行为,但在将它们转换为另一种之前,应先了解它们的细微差别。

STRING 将其所有数据视为字符,或更具体地说,将其视为Unicode代码点。 BYTES将其所有数据视为字节字符串。在实现上的这种差异可能导致行为发生显着不同。例如,让我们采用一个复杂的Unicode字符,例如 (雪人表情符号):

> SELECT length('☃'::string);
  length
+--------+
       1
> SELECT length('☃'::bytes);
  length
+--------+
       3

在这种情况下,LENGTH(string)测量字符串中存在的Unicode代码点的数量,而LENGTH(bytes)测量存储该值所需的字节数。每个字符(或Unicode代码点)可以使用多个字节进行编码,因此两者之间的输出差异。

将文字转换为STRINGBYTES

通过SQL客户端输入的文字将根据类型转换为其他值:

  • BYTES在开头对\x赋予特殊含义,并通过将十六进制数字对替换为单个字节来转换其余部分。例如,\xff等效于值为255的单个字节。
  • STRING没有给\x赋予特殊含义,因此所有字符都被视为不同的Unicode代码点。例如,\xff被视为长度为4(\xf,和f)的STRING

COLLATE

COLLATE功能使您可以根据特定的语言和国家/地区的规则(称为排序规则)对STRING值进行排序。

排序后的字符串很重要,因为不同的语言对于字母顺序(尤其是重音字母)有不同的规则。例如,在德语中,重音字母与非重音字母一起排序,而在瑞典语中,带重音字母则放在字母的末尾。排序规则是用于排序的一组规则,通常对应于一种语言,尽管某些语言具有多个排序不同的排序规则;例如,葡萄牙语对巴西和欧洲方言分别使用排序规则(分别为pt-BRpt-PT)。

细节

对整理字符串进行的操作,不能涉及排序规则不同的字符串或不具有排序规则的字符串。但是,可以动态添加或覆盖排序规则。

仅在需要按特定排序规则对字符串排序时才使用排序规则功能。我们之所以建议这样做,是因为每次构造或加载排序后的字符串到内存中时,数据库都会计算排序键,其大小与排序后的字符串的长度呈线性关系,此过程还需要额外的资源。

排序后的字符串可能比相应的未排序后的字符串大得多,具体取决于语言和字符串内容。例如,包含字符é的字符串在法语语言环境中比在中文语言中产生更大的排序键。

与未排序的字符串相比,为排序后字符串创建索引需要更多的磁盘空间。如果是索引排序后字符串,则除了要存储排序后的字符串之外,还必须存储排序键。

支持的排序

支持Go语言包提供的排序规则。 <collation>参数是每行末尾的BCP 47语言标记,紧跟前面的//。例如,支持南非荷兰语作为AF进行排序

SQL句法

归类的字符串在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类型注释或强制为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 00:00:00+00:00 | 12345  
  2016-03-27 00:00:00+00:00 | 12345 
+---------------------------+-------+
(2 rows)

支持的转换

DATE值可以强制转换为以下任何数据类型:

类型细节
DECIMAL转换为Unix时间至今的天数(1970年1月1日)
FLOAT转换为Unix时间至今的天数(1970年1月1日)
TIMESTAMP将结果时间戳记中的时间设置为00:00(午夜)。
INT转换为Unix时间至今的天数(1970年1月1日)
STRING--

DECIMAL

DECIMAL数据类型存储精确的小数。当保留精确的精度很重要时可以使用此类型,例如,使用货币数据。

别名

DECNUMRICDECIMAL的别名

精度和刻度

使用DECIMAL(precision,scale)限制DECIMAL列,其中precision是小数点左边和右边的最大位数,而scale是小数点右边的精确位数。precision不能小于scale。使用DECIMAL(precision)等效于DECIMAL(precision,0)

插入十进制值时:

  • 如果小数点右边的数字超过该列的小数位数scale,则将四舍五入到scale
  • 如果小数点右边的数字小于列的小数位数scale,则填充0直到scale
  • 如果小数点左右的数字超过该列的精度precision,则会报误。
  • 如果列的precisionscale相同,则插入的值必须四舍五入到小于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 值可以强制转换为以下任何数据类型:

类型细节
BOOL0转换为false;所有其他值都转换为true
FLOAT丢失精度,如果值的太大,则可能会四舍五入到+/-无穷大;如果值的大小,则可能会四舍五入到+/- 0
INT截断小数的精度
STRING--

FLOAT

支持各种不精确的浮点数数据类型,最高可达17位小数精度。它们在内部使用标准的双精度(64位二进制编码)IEEE754格式进行处理。

别名

NameAliases
FLOATNone
REALFLOAT4
DOUBLE PRECISIONFLOAT8

语法

数值文本可以作为浮点类型的输入。例如: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.0123456789012346 | +Inf  
(1 row)
# Note that the value in "b" has been limited to 17 digits.

支持的转换

DECIMAL 值可以强制转换为以下任何数据类型:

类型细节
BOOL0转换为false;所有其他值都转换为true
DECIMAL如果值为NaN或+/- Inf,则会报告错误。
INT截断小数精度,并要求值介于-2 ^ 63和2 ^ 63-1之间
STRING--

INET

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 00:00:00+00:00  
  192.168.0.1                          | info@google.com   | 2018-01-31 00:00:00+00:00  
  2001:4f8:3:ba:2e0:81ff:fe22:d1f1/120 | test@google.com   | 2018-01-31 00:00:00+00:00  
(3 rows)

支持的转换

INET值可以强制转换为以下数据类型:

  • STRING-转换为'Address/subnet'格式。

INT

支持各种有符号整数数据类型。

名称和别名

名称允许的宽度别名范围
INT64-bitINTEGER INT8 INT64 BIGINT-9223372036854775807 到 +9223372036854775807
INT216-bitSMALLINT-32768 到 +32767
INT432-bitNone-2147483648 到 +2147483647
INT864-bitINT-9223372036854775807 到 +9223372036854775807

语法

数值文本可以作为INT类型的输入。例如:42-12340xCAFE

大小

不同的整数类型对允许值的范围设置了不同的约束,但是无论类型如何,所有整数都以相同的方式存储。较小的值比较大的值占用更少的空间(基于数值,而不是数据类型)。

64位有符号整数的注意事项

默认情况下,INTINT8的别名,它将创建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,以使INTSERIAL成为32位整数INT4SERIAL4的别名。

  1. default_int_size 会话变量。
  2. 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值可以强制转换为以下数据类型:

TypeDetails
DECIMAL––
FLOAT如果INT值的大小大于2 ^ 53,则会失去精度。
BIT转换为整数值的二进制表示形式。如果该值为负,则在左侧复制符号位以填充整个位数组。
BOOL0转换为false;所有其他值都将转换为true。
DATE转换为自Unix时间至今的日子(1970年1月1日)
TIMESTAMP转换为自Unix时间至今的日子(1970年1月1日)
INTERVAL转换为微秒。
STRING––

INTERVAL

INTERVAL数据类型存储一个表示时间跨度的值。

别名

INTERVAL(6)

注意 : 支持INTERVAL(6)作为别名仅出于兼容性目的。此别名不能确定INTERVAL值的大小。

语法

INTERVAL类型的常量值可以使用解释后的文字或用INTERVAL类型注解的字符串或强制为INTERVAL类型的字符串文字来表示。

INTERVAL常数可以使用以下格式表示:

格式描述
标准SQLINTERVAL 'Y-M D H:M:S' Y-M D: 使用单个值仅定义天数;使用两个值定义年份和月份。值必须是整数。 H:M:S: 使用单个值仅定义秒;使用两个值定义小时和分钟。值可以是整数或浮点数。
ISO 8601INTERVAL 'P1Y2M3DT4H5M6S'
传统PostgreSQLINTERVAL '1 year 2 months 3 days 4 hours 5 minutes 6 seconds'
简略PostgreSQLINTERVAL '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 值可以强制转换为以下数据类型:

TypeDetails
INT转换为秒数(秒精度)
DECIMAL换为秒数(微秒精度)
FLOAT转换为皮秒数
STRING转换为h-m-s格式(微秒精度)
TIME转换为HH:MM:SS.SSSSSS,该时间等于午夜后的时间间隔(微秒精度)

JSONB

JSONB数据类型将JSON数据存储为JSONB值的二进制存储,从而消除了空格,重复键和键顺序。 JSONB支持倒排索引。

别名

JSONJSONB的别名。

注意 : 在PostgreSQL中,JSONBJSON是两种不同的数据类型。这里的 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值的大小是可变的,但建议将值保持在1 MB以下以确保性能。超过该阈值,写放大和其他考虑因素可能导致性能显着下降。

JSONB函数

FunctionDescription
jsonb_array_elements()JSONB数组扩展为一组JSONB值。
jsonb_build_object(...)从可变参数列表中构建一个JSONB对象,该参数列表在键和值之间交替。
jsonb_each()将最外面的JSONB对象扩展为一组键值对。
jsonb_object_keys()返回最外面的JSONB对象中的有序键集合。
jsonb_pretty()返回给定的JSONB值作为缩进的STRING。请参见下面的示例。

有关受支持的JSONB函数的完整列表 。

JSONB操作符

OperatorDescriptionExample
->访问JSONB字段,返回JSONBSELECT '[{"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数据,请使用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   
+------------+------------+
  "Wang"     | "ShangHai"  
  "Zhang"    | "Beijing"   
(2 rows)

还可以使用 ->> 运算符将 JSONB 字段值作为STRING值返回:

> SELECT user_profile->>'first_name' as first_name,user_profile->>'location' as location FROM users;
  first_name | location  
+------------+----------+
  Wang       | ShangHai  
  Zhang      | Beijing   
(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

SERIAL并非实际的数据类型,在定义一个表的列时,可以代替实际数据类型。它大约等效于使用带有DEFAULT表达式的整数类型,该整数类型在每次求值时都会生成不同的值。该默认表达式进而确保未指定此列的插入将收到自动生成的值,而不是NULL

注意 :提供SERIAL仅是为了与PostgreSQL兼容。应用程序应使用实际数据类型和合适的DEFAULT表达式。

大部分情况下,建议使用带有gen_random_uuid()函数的UUID数据类型作为默认值,该值生成128位值(大于SERIAL的最大64位),并将它们更均匀地分散在表的所有基础键值范围内。当在索引或主键中使用UUID列时,UUID可以确保多个节点共担负载。

操作方式

关键字SERIALCREATE TABLE时可以识别,并在创建表时自动转换为实际数据类型和DEFAULT表达式。转换结果为数据库内部进行,并且可以使用SHOW CREATE进行查看。

选择的DEFAULT表达式可确保在行插入期间自动为列生成不同的值。这些值不能保证单调递增,有关详细信息,请参阅下面的文档。

SERIAL有三种可能的翻译模式:

模式描述
rowid (默认)SERIAL表示默认为unique_rowid()。实际数据类型始终为INT
virtual_sequenceSERIAL创建一个虚拟序列,表示DEFAULT nextval。实际数据类型始终为INT
sql_sequenceSERIAL创建常规SQL序列,表示DEFAULT nextval。实际数据类型取决于SERIAL变体。

模式rowidvirtual_sequence的生成值

rowidvirtual_sequence两种模式下,都会使用unique_rowid()函数自动生成一个值。这将从执行INSERTUPSERT操作的节点的当前时间戳和ID生成64位整数。从统计上讲,此操作在全球范围内可能是唯一的,除非是极端情况。

另外,由于使用unique_rowid()生成的值不需要节点间的协调,因此当多个SQL客户端从不同节点向表写入数据时,它比下面讨论的其他模式sql_sequence快得多。

模式sql_sequence的生成值

在这种模式下,在指定SERIAL的表的同时,自动创建常规SQL序列。

实际数据类型确定如下:

SERIAL 变体实际数据类型
SERIAL2, SMALLSERIALINT2
SERIAL4INT4
SERIALINT
SERIAL8, BIGSERIALINT8

每当使用插入或更新插入时都将使用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中运行以下示例:

  1. 创建一个带有SERIAL列的表:

    > CREATE TABLE increment (a SERIAL PRIMARY KEY);
  2. 运行四个事务以插入行:

    > 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;
  3. 查看创建的行:

    > SELECT * from increment;
    +---+
    | a |
    +---+
    | 2 |
    | 4 |
    +---+

    由于每个插入将a列中的序列加1,因此第一个提交的插入的值为2,第二个提交的插入的值为4。如您所见,这些值不是严格顺序的,最后一个值不能准确计算表中的行数。

总之,PostgreSQL和本数据库中的SERIAL类型以及MySQL中的AUTO_INCREMENT类型都表现一致,因为它们不创建严格的序列。与其他数据库相比,本数据库可能会产生更多的空白间隔,但生成这些值的速度会更快。

其他示例

如果同时发生两个事务,则本数据库无法保证ID单调递增(即第一次提交小于第二次提交)。下面是三个演示此情况的方案:

案例1:

  • 时间点1,事务T1开始。
  • 时间点2,事务T2在同一节点(来自不同的客户端)开始。
  • 时间点3,事务T1创建一个SERIALx
  • 时间点3 + 2微秒,事务T2创建一个SERIALy
  • 时间点4,事务T1提交。
  • 时间点5,事务T2提交。

如果发生这种情况,尽管T1T2开始和提交时间并不同,但本数据库无法保证x<y还是x>y。在这个特定示例中,甚至可能是因为差异小于10微秒导致x=y,并且SERIAL值是根据当前时间的微秒数构造的。

案例2:

  • 时间点1,事务T1开始。
  • 时间点1,事务T2在其他节点上的其他地方开始。
  • 时间点2,事务T1创建一个SERIALx
  • 时间点3,事务T2创建一个SERIALy
  • 时间点3,事务T2创建一个SERIALy
  • 时间点4,事务T1提交。
  • 时间点4,事务T2提交。

如果发生这种情况,本数据库无法保证x<yx>y。即使事务是同时开始和提交的,两者都可能发生。但是,明确的是x!=y,因为这些值是在不同的节点上生成的。

案例3:

  • 时间点1,事务T1开始。
  • 时间点2,事务T1创建一个SERIALx
  • 时间点3,事务T1提交。
  • 时间点4,事务T2在其他节点上的其他地方开始。
  • 时间点5,事务T2创建SERIALy
  • 时间点6,事务T2提交。

两个节点的系统时钟之间的差异小于250微秒。

如果发生这种情况,本数据库无法保证x<yx>y。即使事务明显地发生在另一个之后,也可能在两个节点之间存在时钟偏差,并且第二个节点的系统时间设置得比第一个节点稍早。


STRING

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值的大小是可变的,但建议将值保持在64 KB以下以确保性能。超过该阈值,写放大和其他考虑因素可能导致性能显着下降。

示例

> 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值强制转换为以下任何数据类型:

类型细节
BIT需要支持BIT字符串类型, 如: '101001'.
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字符串类型, 如: '1h2m3s4ms5us6ns'.
TIME需要支持TIME字符串类型, 如: '01:22:12' (微秒精度).
TIMESTAMP需要支持TIMESTAMP字符串类型, 如: '2019-01-28 10:10:10.222222'.
STRING vs. BYTES

尽管在许多情况下,STRINGBYTES似乎都具有相似的行为,但在将它们转换为另一种之前,应先了解它们的细微差别。

STRING将其所有数据视为字符,或更具体地说,将其视为Unicode代码点。 BYTES将其所有数据视为字节字符串。在实现上的这种差异可能导致行为发生显着不同。例如,让我们采用一个复杂的Unicode字符,例如(雪人表情符号):

> SELECT length('☃'::string);
  length
+--------+
       1
> SELECT length('☃'::bytes);
  length
+--------+
       3

在这种情况下,LENGTH(string)测量字符串中存在的Unicode代码点的数量,而LENGTH(bytes)测量存储该值所需的字节数。每个字符(或Unicode代码点)可以使用多个字节进行编码,因此两者之间输出存在差异。

将文字转换为STRINGBYTES

通过SQL客户端输入的文字将根据类型转换为其他值:

  • BYTES在开头对\x赋予特殊含义,并通过将十六进制数字对替换为单个字节来转换其余部分。例如,\xff等效于值为255的单个字节。
  • STRING没有给\x赋予特殊含义,因此所有字符都被视为不同的Unicode代码点。例如,\xff被视为长度为4(\xff)的STRING

TIME

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 | 0000-01-01 08:40:00+00:00  
        2 | 0000-01-01 08:41:40+00:00  
(2 rows)

比较TIME值:

> SELECT (SELECT time_val FROM time WHERE time_id = 1) < (SELECT time_val FROM time WHERE time_id = 2);
(SELECT time_val FROM "time"  WHERE time_id = 1) < (SELECT  time_val FROM "time" WHERE  time_id = 2)          
+--------------------------------------------------------------------------------------+
              true              
(1 row)

支持的转换

可以将TIME 值强制转换为以下任何数据类型:

类型细节
INTERVAL转换为从午夜(00:00)开始的时间范围
STRING转换为格式“ HH:MM:SS.SSSSSS”(微秒精度)

TIMESTAMP / TIMESTAMPTZ

TIMESTAMPTIMESTAMPTZ数据类型以UTC格式存储日期和时间对。

变体

TIMESTAMP有两个变形:

  • TIMESTAMP以UTC形式表示所有TIMESTAMP值。
  • TIMESTAMPTZTIMESTAMP值从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 onlyTIMESTAMP '2016-01-25'
Date and TimeTIMESTAMP '2016-01-25 10:10:10.555555'
ISO 8601TIMESTAMP '2016-01-25T10:10:10.555555'

要表示TIMESTAMPTZ值(时区与UTC偏移),请使用以下格式:TIMESTAMPTZ '2019-02-25 10:10:10.555555-05:00'

如果明确,简单的未注释字符串文字也可以自动解释为TIMESTAMPTIMESTAMPTZ类型。

请注意,小数部分是可选的,并且四舍五入到微秒(十进制后的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-05:00'), (2, TIMESTAMPTZ '2019-03-25');
> SELECT * FROM timestamps;
  a |             b              
+---+---------------------------+
  1 | 2019-03-25 15:10:10+00:00  
  2 | 2019-03-25 00:00:00+00:00  
(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

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 用作URNUUID可以用作统一资源名称(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的表

要自动生成唯一的行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需要支持BYTES 字符串格式 , 如: b'\141\061\142\062\143\063'.