数据类型

Cloud Spanner 不但支持简单的数据类型(如整数),还支持更为复杂的类型(如 ARRAY 和 STRUCT)。此页面概述了每种数据类型,包括允许使用的值。

列值的大小上限为 10MiB,适用于标量和数组类型。

允许的类型

类型名称 是否为有效的列类型? 是否为有效的键列类型? 1 是否为有效的 SQL 类型? 存储空间大小2
ARRAY 元素大小的总和
BOOL 1 个字节
BYTES 字节数
DATE 4 个字节
FLOAT64 8 个字节
INT64 8 个字节
NUMERIC 用于存储值的精度和标度的函数。值 0 存储为 1 个字节。其他所有值的存储空间大小介于 6 到 22 个字节之间。
STRING UTF-8 编码的字节数
STRUCT 不适用
TIMESTAMP 12 个字节

1 主键、外键、二级索引。
2 除了列出的值之外,每个单元还占用 8 个字节的存储空间。

数据类型属性

在存储和查询数据时,记住以下数据类型属性会很有帮助:

属性 说明 应用对象
可以为 Null NULL 是一个有效值。 所有数据类型。
可排序 可在 ORDER BY 子句中使用。 除以下类型之外的其他所有数据类型:
  • ARRAY
  • STRUCT
可分组 一般可以出现在
GROUP BYDISTINCT 后面的表达式中。
除以下类型之外的其他所有数据类型:
  • ARRAY
  • STRUCT
可比较 相同类型的值可以相互比较。 所有数据类型,但存在以下例外情况:不支持 ARRAY 比较。

系统支持按字段顺序对 STRUCT 进行逐个字段的相等性比较。 字段名称会被忽略。不支持小于和大于比较。

所有支持比较的类型均可用于 JOIN 条件。如需了解联接条件的说明,请参阅 JOIN 类型

数值类型

数值类型包括整数类型、浮点类型和 NUMERIC 数据类型。

整数类型

整数是指不含小数部分的数值。

姓名 范围
INT64 -9,223,372,036,854,775,808 至 9,223,372,036,854,775,807

NUMERIC 类型

NUMERIC 数据类型属于精确数值,其精度为 38 位、标度为 9 位。精度是指数字所包含的位数。标度是指小数点后的位数。

此类型可以精确表示小数部分,适用于财务计算。

姓名 说明 范围
NUMERIC 精度为 38 位、标度为 9 位的十进制值。 -99999999999999999999999999999.999999999 至 99999999999999999999999999999.999999999
NUMERIC 不是有效的键列,且不能用于主键、外键或索引。

浮点类型

浮点值是含有小数部分的近似数值。

姓名 说明
FLOAT64 双精度(近似)小数值。

浮点语义

使用浮点数时,需要考虑特殊的非数值:NaN+/-inf

使用 Cloud Spanner REST API 和 RPC API 时,请将特殊浮点值的格式设置为 Infinity-InfinityNaN,如 TypeCode (REST)TypeCode (RPC) 中所述。Cloud Spanner REST API 和 RPC API 不支持 +inf-infnan 字面量。

算术运算符可为产生有限输出的所有有限输入值和至少有一个非有限输入的所有运算提供标准 IEEE-754 行为。

如果输入有限,但输出非有限,则函数调用和运算符会返回溢出错误。如果输入包含非有限值,则输出可以是非有限的。一般而言,函数不会引入 NaN+/-inf。但是,像 IEEE_DIVIDE 这样的特定函数可以为有限输入返回非有限值。所有此类情况都会在数学函数中明确指出。

数学函数示例
左侧运算对象 运算符 右侧运算对象 返回值
任意值 + NaN NaN
1.0 + +inf +inf
1.0 + -inf -inf
-inf + +inf NaN
最大 FLOAT64 + 最大 FLOAT64 溢出错误
最小 FLOAT64 / 2.0 0.0
1.0 / 0.0 “除以零”错误

比较运算符为浮点输入提供标准的 IEEE-754 行为。

比较运算符示例
左侧运算对象 运算符 右侧运算对象 返回值
NaN = 任意值 FALSE
NaN < 任意值 FALSE
任意值 < NaN FALSE
-0.0 = 0.0 TRUE
-0.0 < 0.0 FALSE

浮点值会按以下顺序排序(从最小值到最大值):

  1. NULL
  2. NaN - 排序时,所有 NaN 值都会被视为相等。
  3. -inf
  4. 负数
  5. 0 或 -0 - 排序时,所有零值被视为相等。
  6. 正数
  7. +inf

特殊浮点值按以下方式分组,包括由 GROUP BY 子句完成的分组和由 DISTINCT 关键字完成的分组:

  • NULL
  • NaN - 分组时,所有 NaN 值都会被视为相等。
  • -inf
  • 0 或 -0 - 分组时,所有零值都会被视为相等。
  • +inf

布尔值类型

名称 说明
BOOL 布尔值由关键字 TRUEFALSE(不区分大小写)表示。

字符串类型

名称 说明
STRING 长度可变的字符 (Unicode) 数据。

输入的 STRING 值必须采用 UTF-8 编码,输出的 STRING 值同样采用 UTF-8 编码。CESU-8 和经过修改的 UTF-8 等替代编码被视为无效的 UTF-8 编码。

所有作用于 STRING 值的函数和运算符都会对 Unicode 字符(而非字节)进行运算。例如,应用于 STRING 输入的函数(如 SUBSTRLENGTH)计算的是字符数,而非字节数。

每个 Unicode 字符都有一个分配给它的称为代码点的数值。 较低的代码点分配给较低位的字符。比较字符时,代码点决定了哪些字符小于或大于其他字符。

STRING 的大多数函数在 BYTES 中也存在定义,但 BYTES 的那些函数会针对原始字节(而非 Unicode 字符)进行运算。STRING 和 BYTES 是不能互换使用的独立类型。任何方向都不存在隐式类型转换。STRING 和 BYTES 之间的显式类型转换采用 UTF-8 编码和解码。如果字节不是有效的 UTF-8 编码,则将 BYTES 转换为 STRING 时会返回错误。

字节类型

名称 说明
BYTES 长度可变的二进制数据。

STRING 和 BYTES 是不能互换使用的独立类型。STRING 的大多数函数在 BYTES 中也存在定义,但 BYTES 的那些函数会针对原始字节(而非 Unicode 字符)进行运算。STRING 和 BYTES 之间的类型转换会强制使用 UTF-8 对字节进行编码。

日期类型

名称 范围
DATE 0001-01-01 至 9999-12-31。

DATE 类型表示逻辑日历日期,与时区无关。DATE 值不代表特定的 24 小时时间段。给定的 DATE 值在不同时区下表示不同的 24 小时时间段,并且可能代表夏令时转换期间较短或较长的一天。 如需表示绝对的时间点,请使用时间戳

标准格式
'YYYY-[M]M-[D]D'
  • YYYY:以四位数字表示的年份
  • [M]M:以一位或两位数字表示的月份
  • [D]D:以一位或两位数字表示的日期

时间戳类型

名称 范围
TIMESTAMP 世界协调时间 (UTC) 0001-01-01 00:00:00 至 9999-12-31 23:59:59.999999999。

TIMESTAMP 对象表示绝对时间点,与任何时区或惯例(如夏令时)无关,可精确到纳秒。

  • 如需按日历上显示的方式来表示日期,请使用 DATE 对象。
标准格式

对于 Rest API 和 RPC API

按照 TypeCode (RPC)TypeCode (REST) 中所述的规则对 JSON 值进行编码和解码。尤其要注意的是,时间戳值必须以大写字母“Z”结束以指定祖鲁时间 (UTC-0)。

例如:

2014-09-27T12:30:00.45Z

时间戳值必须以祖鲁时间表示,且不能包含 UTC 偏移量。例如,以下时间戳不受支持:

-- NOT SUPPORTED! TIMESTAMPS CANNOT INCLUDE A UTC OFFSET WHEN USED WITH THE REST AND RPC APIS
2014-09-27 12:30:00.45-8:00

对于客户端库

使用特定于语言的时间戳格式。

对于 SQL 查询

YYYY-[M]M-[D]D[( |T)[H]H:[M]M:[S]S[.DDDDDDDDD]][time zone]
  • YYYY:以四位数字表示的年份
  • [M]M:以一位或两位数字表示的月份
  • [D]D:以一位或两位数字表示的日期
  • ( |T):空格或“T”分隔符
  • [H]H:以一位或两位数字表示的小时(有效值为 00 到 23)
  • [M]M:以一位或两位数字表示的分钟(有效值为 00 到 59)
  • [S]S:以一位或两位数字表示的秒钟(有效值为 00 到 59)
  • [.DDDDDDDDD]:最多九个小数位(精度为纳秒)
  • [time zone]:表示时区的字符串。 未明确指定时区时,将使用 America/Los_Angeles 默认时区。如需了解详情,请参阅时区部分。

时区

在解析时间戳或设置其格式以用于显示时,会用到时区。时间戳值本身不会存储特定的时区,也不会在应用时区偏移时发生更改。

时区由以下任一标准格式的字符串表示:

  • 相对于世界协调时间 (UTC) 的偏移量,或代表 UTC 的字母 Z
  • tz 数据库中的时区名称

相对于世界协调时间 (UTC) 的偏移量

(+|-)H[H][:M[M]]
Z

示例

-08:00
-8:15
+3:00
+07:30
-7
Z

使用此格式时,时区和时间戳的其余部分之间不允许留有空格。

2014-09-27 12:30:00.45-8:00
2014-09-27T12:30:00.45Z

时区名称

continent/[region/]city

时区名称来自 tz 数据库。 请参阅维基百科上的 tz 数据库时区列表,其中提供了虽不全面但较为简单的参考信息。

示例

America/Los_Angeles
America/Argentina/Buenos_Aires

使用时区名称时,名称和时间戳的其余部分之间必须留有空格:

2014-09-27 12:30:00.45 America/Los_Angeles

注意:并非所有时区名称都可以互换,即使这些时区在一年当中的某些特定期间恰好报告了相同的时间。例如,在夏令时期间,America/Los_Angeles 报告的时间与 UTC-7:00 相同;但在非夏令时期间,其报告的时间与 UTC-8:00 相同。

如果未指定时区,则使用默认时区值。

闰秒

时间戳只是相对于世界协调时间 (UTC) 1970-01-01 00:00:00 的偏移量(假设每分钟正好 60 秒)。存储的时间戳不能表示闰秒。

如果输入包含在秒钟字段中使用“:60”来表示闰秒的值,则系统不会在转换为时间戳值时保留该闰秒,而是会将该值解释为下一分钟的时间戳(秒钟字段的值为“:00”)。

闰秒不会影响时间戳的计算。所有时间戳均使用 Unix 样式的时间戳进行计算,而这种样式的时间戳不能体现闰秒。闰秒只能通过测定真实世界时间的函数进行观察。在这些函数中,若存在闰秒,系统可能会跳过或重复时间戳的秒值。

数组类型

名称 说明
ARRAY 任何非 ARRAY 类型的零个或零个以上元素的有序列表。

ARRAY 是一个包含零个或零个以上非 ARRAY 值元素的有序列表。不允许使用由 ARRAY 组成的 ARRAY。如果查询会产生由 ARRAY 组成的 ARRAY,则会返回错误。正确的做法是,您必须使用 SELECT AS STRUCT 结构在 ARRAY 之间插入 STRUCT。

空 ARRAY 和 NULL ARRAY 是两个不同的值。ARRAY 可以包含 NULL 元素。

声明 ARRAY 类型

ARRAY<T>

您可以使用尖括号(<>)来声明 ARRAY 类型。ARRAY 的元素可以是任意复杂类型,但 ARRAY 不能直接包含另一个 ARRAY。

示例

类型声明 含义
ARRAY<INT64> 由 64 位整数组成的简单 ARRAY 类型。
ARRAY<STRUCT<INT64, INT64>> 由 STRUCT 组成的 ARRAY 类型,其中每个 STRUCT 包含两个 64 位整数。
注意:由 STRUCT 组成的 ARRAY 的值可以由 SQL 表达式进行构造,但不支持作为列类型。
ARRAY<ARRAY<INT64>>
(不受支持)
这是一个无效的类型声明,列于此处的目的在于防止您来此查找创建多层 ARRAY 的相关信息。ARRAY 不能直接包含 ARRAY。请参阅下一个示例。
ARRAY<STRUCT<ARRAY<INT64>>> 由 64 位整数 ARRAY 组成的 ARRAY 类型。请注意,两个 ARRAY 之间存在 STRUCT,因为 ARRAY 不能直接包含其他 ARRAY。
注意:由 STRUCT 组成的 ARRAY 的值可以由 SQL 表达式进行构造,但不支持作为列类型。

结构体类型

如需详细了解如何在 SELECT 语句子查询中使用 STRUCT,请参阅“查询语法”页面。

名称 说明
STRUCT 有序字段的容器,其中每个字段都有一个类型(必需)和字段名称(可选)。

声明 STRUCT 类型

STRUCT<T>

您可以使用尖括号(<>)来声明 STRUCT 类型。STRUCT 的元素可以是任意复杂类型。

注意:STRUCT 值可以由 SQL 表达式进行构造,但不支持作为列类型。

示例

类型声明 含义
STRUCT<INT64> 具有单个未命名 64 位整数字段的简单 STRUCT 类型。
STRUCT<x STRUCT<y INT64, z INT64>> 具有名为 x 的嵌套 STRUCT 的 STRUCT 类型。STRUCT x 具有 yz 两个字段,二者都是 64 位整数。
STRUCT<inner_array ARRAY<INT64>> 包含名为 inner_array 的 ARRAY 且 ARRAY 由 64 位整数元素组成的 STRUCT 类型。

构造 STRUCT

元组语法

(expr1, expr2 [, ... ])

输出类型是具有匿名字段的匿名 STRUCT 类型,其类型与输入表达式的类型相匹配。必须指定至少两个表达式。否则无法区分该语法与用圆括号括起来的表达式。

示例

语法 输出类型 说明
(x, x+y) STRUCT<?,?> 如果使用列名称(未加引号的字符串),则 STRUCT 字段数据类型由列数据类型派生而来。xy 是列,因此 STRUCT 字段的数据类型由列类型和加法运算符的输出类型派生而来。

对于使用多部分键的比较表达式,此语法还可与 STRUCT 比较搭配使用,例如,在 WHERE 子句中:

WHERE (Key1,Key2) IN ( (12,34), (56,78) )

无类型结构体语法

STRUCT( expr1 [AS field_name] [, ... ])

允许使用重复的字段名称。没有名称的字段会被视为匿名字段,不能通过名称进行引用。STRUCT 的值可以为 NULL,也可以拥有 NULL 字段值。

示例

语法 输出类型
STRUCT(1,2,3) STRUCT<int64,int64,int64>
STRUCT() STRUCT<>
STRUCT('abc') STRUCT<string>
STRUCT(1, t.str_col) STRUCT<int64, str_col string>
STRUCT(1 AS a, 'abc' AS b) STRUCT<a int64, b string>
STRUCT(str_col AS abc) STRUCT<abc string>

类型化结构体语法

STRUCT<[field_name] field_type, ...>( expr1 [, ... ])

类型化语法允许使用显式 STRUCT 数据类型来构造 STRUCT。输出类型与提供的 field_type 类型完全一致。如果两种类型不相同,则输入表达式会被强制转换为 field_type 指定的类型;如果类型不兼容,则会产生错误。输入表达式不允许使用 AS alias。表达式的数量必须与类型中的字段数相匹配,并且表达式类型必须可强制转换或字面上强制转换为字段类型。

示例

语法 输出类型
STRUCT<int64>(5) STRUCT<int64>
STRUCT<date>("2011-05-05") STRUCT<date>
STRUCT<x int64, y string>(1, t.str_col) STRUCT<x int64, y string>
STRUCT<int64>(int_col) STRUCT<int64>
STRUCT<x int64>(5 AS x) 错误 - 类型化语法不允许使用 AS

STRUCT 的有限比较

可以使用等号运算符直接比较 STRUCT:

  • 等于 (=)
  • 不等于(!=<>
  • [NOT] IN

但是请注意,这些直接相等性比较会按顺序成对比较 STRUCT 的字段,并忽略字段名称。如果您希望比较 STRUCT 的同名字段,则可直接比较个别字段。