标准 SQL 中的数据类型

BigQuery 不但支持简单的数据类型(如整数),还支持更为复杂的类型(如 ARRAY 和 STRUCT)。本页面简要介绍了各种数据类型,包括允许使用的值。如需了解数据类型字面量和构造函数,请参阅词法结构和语法

数据类型属性

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

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

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

不支持 GEOGRAPHY 比较。要比较 GEOGRAPHY 值,请使用 ST_Equals

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

参数化数据类型

语法:

DATA_TYPE(param[, ...])

您可以使用参数为以下数据类型指定限制条件:

  • STRING
  • BYTES
  • NUMERIC
  • BIGNUMERIC

使用参数声明的数据类型称为参数化数据类型。您只能将参数化数据类型用于列和脚本变量。使用参数化数据类型的列为参数化列,使用参数化数据类型的脚本变量为参数化脚本变量。将值写入参数化列或将值分配给参数化脚本变量时,系统会强制执行参数化类型限制条件。

数据类型的参数不会传播到表达式,只有数据类型会被传播。

示例

-- Declare a variable with type parameters.
DECLARE x STRING(10);

-- This is a valid assignment to x.
SET x = "hello";

-- This assignment to x violates the type parameter constraint and results in an OUT_OF_RANGE error.
SET x = "this string is too long"
-- Declare variables with type parameters.
DECLARE x NUMERIC(10) DEFAULT 12345;
DECLARE y NUMERIC(5, 2) DEFAULT 123.45;

-- The variable x is treated as a NUMERIC value when read, so the result of this query
-- is a NUMERIC without type parameters.
SELECT x;

-- Type parameters are not propagated within expressions, so variables x and y are treated
-- as NUMERIC values when read and the result of this query is a NUMERIC without type parameters.
SELECT x + y;

数组类型

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

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

目前,BigQuery 在 NULL 和 ARRAY 方面有以下两项限制:

  • 如果查询结果具有包含 NULL 元素的 ARRAY,那么尽管可以在查询中使用这些 ARRAY,BigQuery 仍会引发错误。
  • 尽管在查询中 NULL ARRAY 和空 ARRAY 是两个不同的值,但 BigQuery 会在查询结果中将 NULL ARRAY 转换为空 ARRAY。

声明 ARRAY 类型

ARRAY<T>

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

示例

类型声明 含义
ARRAY<INT64> 由 64 位整数组成的简单 ARRAY 类型。
ARRAY<BYTES(5)> 预览版 由参数化字节组成的简单 ARRAY 类型。
ARRAY<STRUCT<INT64, INT64>> 由 STRUCT 组成的 ARRAY 类型,其中每个 STRUCT 包含两个 64 位整数。
ARRAY<ARRAY<INT64>>
(不受支持)
这是一个无效的类型声明,列于此处的目的在于防止您来此查找创建多层 ARRAY 的相关信息。ARRAY 不能直接包含 ARRAY。请参阅下一个示例。
ARRAY<STRUCT<ARRAY<INT64>>> 由 64 位整数 ARRAY 组成的 ARRAY 类型。请注意,两个 ARRAY 之间存在 STRUCT,因为 ARRAY 不能直接包含其他 ARRAY。

布尔值类型

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

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

  1. NULL
  2. FALSE
  3. TRUE

字节类型

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

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

参数化字节类型

参数化类型 说明
BYTES(L) 二进制字符串中最多允许 L 个字节的字节序列,其中 L 是一个正 INT64 值。如果字节序列超过 L 个字节,则会抛出 OUT_OF_RANGE 错误。

如需详细了解参数化类型及其使用位置,请参阅参数化数据类型

日期类型

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

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

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

日期时间类型

名称 范围
DATETIME 0001-01-01 00:00:00 至 9999-12-31 23:59:59.999999

DATETIME 对象按照日历或时钟上的显示方式来表示日期和时间,与时区无关。 该对象包含年、月、日、小时、分钟、秒和亚秒部分。 如需表示绝对的时间点,请使用时间戳

标准格式
YYYY-[M]M-[D]D[( |T)[H]H:[M]M:[S]S[.F]]
  • YYYY:以四位数字表示的年份
  • [M]M:以一位或两位数字表示的月份
  • [D]D:以一位或两位数字表示的日期
  • ( |T):空格或“T”分隔符
  • [H]H:以一位或两位数字表示的小时(有效值为 00 到 23)
  • [M]M:以一位或两位数字表示的分钟(有效值为 00 到 59)
  • [S]S:以一位或两位数字表示的秒钟(有效值为 00 到 59)
  • [.F]:最多六个小数位(即高达微秒的精度)

地理位置类型

名称 说明
GEOGRAPHY 点、线和面的集合,表示为一个点集或地球表面的部分区域。

GEOGRAPHY 类型基于 OGC 简单要素规范 (SFS),是以下对象的集合:

  • 点地理位置:坐标空间中的单个位置。点具有 x 坐标值和 y 坐标值,其中 x 坐标为点在 WGS84 参考椭球体上的经度,y 坐标为纬度。
  • 线串地理位置:一维几何对象,包含一系列点和它们之间的测地线边。
  • 多边形地理位置:由 1 个外部边界和 0 个或多个内部边界定义的平面。每个内部边界定义多边形中的一个孔。多边形的边界环是定向的,因此,如果您按顺序遍历边界顶点,则多边形的内部位于左侧。

一个 GEOGRAPHY 值的点、线串和多边形在 WGS84 参考椭球体上形成一个简单排列。简单排列是指集合的多个元素不包含 WGS84 表面上任何点的排列方式。如果存在自相交,系统会自动移除它们。

不包含点、线串或多边形的 GEOGRAPHY 称为空 GEOGRAPHY

GEOGRAPHY地理位置函数的结果或参数。

数值类型

数值类型包括下列类型:

  • INT64
  • NUMERIC,别名为 DECIMAL
  • BIGNUMERIC,别名为 BIGDECIMAL
  • FLOAT64

整数类型

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

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

十进制类型

十进制类型值是具有固定精度和标度的数值。精度是指数字所包含的位数。标度是指小数点后的位数。

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

姓名 精度、标度和范围
NUMERIC
DECIMAL
精度:38
标度:9
最小值:-9.9999999999999999999999999999999999999E+28
最大值:9.9999999999999999999999999999999999999E+28
BIGNUMERIC
BIGDECIMAL
精度:76.76(第 77 位不完整)
小数位:38
最小值:-5.7896044618658097711785492504343953926634992332820282019728792003956564819968E+38
最大值:5.7896044618658097711785492504343953926634992332820282019728792003956564819967E+38

DECIMALNUMERIC 的别名。BIGDECIMALBIGNUMERIC 的别名。

参数化小数类型

参数化类型 说明
NUMERIC(P[,S])
DECIMAL(P[,S])
NUMERICDECIMAL 类型,最大精度为 P,最大标度为 S,其中 PSINT64 类型。如果未指定,则 S 被解释为 0。

最大标度范围:0 ≤ S ≤ 9
最大精度范围:max(1, S) ≤ PS + 29
BIGNUMERIC(P[, S])
BIGDECIMAL(P[, S])
BIGNUMERICBIGDECIMAL 类型,最大精度为 P,最大标度为 S,其中 PSINT64 类型。如果未指定,则 S 被解释为 0。

最大标度范围:0 ≤ S ≤ 38
最大精度范围:max(1, S) ≤ PS + 38

如果值包含的小数位数超过 S,则该值会四舍五入到 S 位小数。例如,如果将值 1.125 插入到 NUMERIC(5, 2) 列中,则会将 1.125 向上舍入到 1.13。

如果值包含的位数超过 P,则会抛出 OUT_OF_RANGE 错误。例如,将 1111 插入 NUMERIC(5, 2) 列会返回 OUT_OF_RANGE 错误,因为 1111 大于 999.99,即 NUMERIC(5, 2) 列中允许的最大值。

如需详细了解参数化类型及其使用位置,请参阅参数化数据类型

浮点类型

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

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

浮点语义

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

算术运算符可为产生有限输出的所有有限输入值和至少有一个非有限输入的所有运算提供标准 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

字符串类型

名称 说明
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 时会返回错误。

参数化字符串类型

参数化类型 说明
STRING(L) 最多允许 L 个 Unicode 字符的字符串,其中 L 是一个正 INT64 值。如果分配的字符串包含的 Unicode 字符数超过 L,则会抛出 OUT_OF_RANGE 错误。

如需详细了解参数化类型及其使用位置,请参阅参数化数据类型

结构体类型

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

声明 STRUCT 类型

STRUCT<T>

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

示例

类型声明 含义
STRUCT<INT64> 具有单个未命名 64 位整数字段的简单 STRUCT 类型。
STRUCT<x STRING(10)> 预览版 具有单个名为 x 的参数化字符串字段的简单 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 的同名字段,则可直接比较个别字段。

时间类型

名称 范围
TIME 00:00:00 至 23:59:59.99999。

TIME 对象按照手表上的显示方式来表示时间,与特定日期和时区无关。 如需表示绝对的时间点,请使用时间戳

标准格式
[H]H:[M]M:[S]S[.DDDDDD|.F]
  • [H]H:以一位或两位数字表示的小时(有效值为 00 到 23)
  • [M]M:以一位或两位数字表示的分钟(有效值为 00 到 59)
  • [S]S:以一位或两位数字表示的秒钟(有效值为 00 到 59)
  • [.F]:最多六个小数位(即高达微秒的精度)

时间戳类型

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

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

  • 如需按日历上显示的方式来表示日期,请使用 DATE 对象。
  • 如需按时钟上显示的方式来表示时间,请使用 TIME 对象。
  • 如需按日历和时钟上显示的方式来表示日期和时间,请使用 DATETIME 对象。
标准格式
YYYY-[M]M-[D]D[( |T)[H]H:[M]M:[S]S[.F]][time zone]
  • YYYY:以四位数字表示的年份
  • [M]M:以一位或两位数字表示的月份
  • [D]D:以一位或两位数字表示的日期
  • ( |T):空格或“T”分隔符
  • [H]H:以一位或两位数字表示的小时(有效值为 00 到 23)
  • [M]M:以一位或两位数字表示的分钟(有效值为 00 到 59)
  • [S]S:以一位或两位数字表示的秒钟(有效值为 00 到 59)
  • [.F]:最多六个小数位(即高达微秒的精度)
  • [time zone]:表示时区的字符串。 如果未明确指定时区,则使用默认时区,即世界协调时间 (UTC)。 如需了解详情,请参阅时区部分。

时区

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

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

  • 世界协调时间 (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 样式的时间戳进行计算,而这种样式的时间戳不能体现闰秒。闰秒只能通过测定真实世界时间的函数进行观察。在这些函数中,若存在闰秒,系统可能会跳过或重复时间戳的秒值。