Spanner数据类型 #

一、数据类型概述 #

1.1 类型分类 #

text
Spanner数据类型
├── 标量类型 (Scalar Types)
│   ├── 数值类型
│   ├── 布尔类型
│   ├── 字符串类型
│   ├── 字节类型
│   ├── 日期时间类型
│   └── JSON类型
│
├── 数组类型 (ARRAY)
│   └── 标量类型的数组
│
└── 结构体类型 (STRUCT)
    └── 命名字段集合

1.2 类型对比表 #

类型 说明 存储大小
BOOL 布尔值 1字节
INT64 64位整数 8字节
FLOAT64 64位浮点数 8字节
STRING 变长字符串 可变
BYTES 变长字节 可变
DATE 日期 4字节
TIMESTAMP 时间戳 12字节
JSON JSON数据 可变
ARRAY 数组 可变
STRUCT 结构体 可变

二、数值类型 #

2.1 INT64 #

sql
-- 64位有符号整数
-- 范围: -9,223,372,036,854,775,808 到 9,223,372,036,854,775,807

CREATE TABLE numbers (
    id INT64 NOT NULL,
    value INT64
) PRIMARY KEY (id);

-- 插入数据
INSERT INTO numbers (id, value) VALUES (1, 1234567890);
INSERT INTO numbers (id, value) VALUES (2, -9876543210);

-- 整数字面量
SELECT 123;                    -- 十进制
SELECT 0x1F;                   -- 十六进制
SELECT 0o17;                   -- 八进制

2.2 FLOAT64 #

sql
-- 64位IEEE 754浮点数
-- 范围: 约 ±1.7976931348623157e308

CREATE TABLE measurements (
    id INT64 NOT NULL,
    temperature FLOAT64,
    pressure FLOAT64
) PRIMARY KEY (id);

-- 插入数据
INSERT INTO measurements (id, temperature, pressure)
VALUES (1, 23.5, 1013.25);

-- 浮点字面量
SELECT 3.14;
SELECT 2.5e10;                 -- 科学计数法
SELECT CAST('inf' AS FLOAT64); -- 无穷大
SELECT CAST('nan' AS FLOAT64); -- 非数字

2.3 数值函数 #

sql
-- 数学函数
SELECT ABS(-123);              -- 绝对值: 123
SELECT ROUND(3.14159, 2);      -- 四舍五入: 3.14
SELECT FLOOR(3.7);             -- 向下取整: 3
SELECT CEIL(3.2);              -- 向上取整: 4
SELECT SQRT(16);               -- 平方根: 4
SELECT POWER(2, 10);           -- 幂运算: 1024
SELECT LOG(100);               -- 自然对数
SELECT LOG10(100);             -- 以10为底的对数: 2

-- 类型转换
SELECT CAST('123' AS INT64);   -- 字符串转整数
SELECT CAST(123 AS FLOAT64);   -- 整数转浮点
SELECT SAFE_CAST('abc' AS INT64); -- 安全转换,失败返回NULL

三、布尔类型 #

3.1 BOOL #

sql
-- 布尔类型,值为 TRUE 或 FALSE

CREATE TABLE flags (
    id INT64 NOT NULL,
    is_active BOOL NOT NULL,
    is_deleted BOOL DEFAULT FALSE
) PRIMARY KEY (id);

-- 插入数据
INSERT INTO flags (id, is_active) VALUES (1, TRUE);
INSERT INTO flags (id, is_active) VALUES (2, FALSE);

-- 布尔字面量
SELECT TRUE;
SELECT FALSE;
SELECT NULL::BOOL;

3.2 布尔运算 #

sql
-- 逻辑运算
SELECT TRUE AND FALSE;         -- FALSE
SELECT TRUE OR FALSE;          -- TRUE
SELECT NOT TRUE;               -- FALSE

-- 比较运算
SELECT 1 = 1;                  -- TRUE
SELECT 1 != 2;                 -- TRUE
SELECT 1 < 2;                  -- TRUE
SELECT 1 > 0;                  -- TRUE
SELECT 1 <= 1;                 -- TRUE
SELECT 1 >= 1;                 -- TRUE

-- NULL处理
SELECT TRUE AND NULL;          -- NULL
SELECT FALSE OR NULL;          -- NULL
SELECT NOT NULL;               -- NULL

-- 安全比较
SELECT 1 IS NULL;              -- FALSE
SELECT NULL IS NULL;           -- TRUE
SELECT NULL IS NOT NULL;       -- FALSE

四、字符串类型 #

4.1 STRING #

sql
-- 变长字符串,必须指定最大长度
-- STRING(n): 最大n个字符
-- STRING(MAX): 最大2,621,442个字符

CREATE TABLE users (
    user_id INT64 NOT NULL,
    name STRING(100) NOT NULL,
    email STRING(255),
    bio STRING(MAX)
) PRIMARY KEY (user_id);

-- 插入数据
INSERT INTO users (user_id, name, email, bio)
VALUES (1, 'John Doe', 'john@example.com', 'A software developer');

-- 字符串字面量
SELECT 'Hello, World!';        -- 普通字符串
SELECT "Hello, World!";        -- 双引号也支持
SELECT r'Raw\nString';         -- 原始字符串,不转义
SELECT '''Multi
line
string''';                      -- 多行字符串

4.2 字符串函数 #

sql
-- 字符串操作
SELECT LENGTH('Hello');        -- 长度: 5
SELECT UPPER('hello');         -- 大写: HELLO
SELECT LOWER('HELLO');         -- 小写: hello
SELECT TRIM('  hello  ');      -- 去空格: hello
SELECT LTRIM('  hello');       -- 去左空格
SELECT RTRIM('hello  ');       -- 去右空格

-- 子字符串
SELECT SUBSTR('Hello', 1, 3);  -- 子串: Hel
SELECT LEFT('Hello', 3);       -- 左边3个: Hel
SELECT RIGHT('Hello', 3);      -- 右边3个: llo

-- 查找和替换
SELECT STRPOS('Hello', 'l');   -- 查找位置: 3
SELECT REPLACE('Hello', 'l', 'L'); -- 替换: HeLLo
SELECT SPLIT('a,b,c', ',');    -- 分割: ['a', 'b', 'c']

-- 拼接
SELECT CONCAT('Hello', ' ', 'World'); -- Hello World
SELECT 'Hello' || ' ' || 'World';     -- Hello World

-- 正则表达式
SELECT REGEXP_CONTAINS('Hello', '^[A-Z]'); -- TRUE
SELECT REGEXP_EXTRACT('Hello123', '[0-9]+'); -- 123
SELECT REGEXP_REPLACE('Hello123', '[0-9]+', '!'); -- Hello!

五、字节类型 #

5.1 BYTES #

sql
-- 变长字节数组
-- BYTES(n): 最大n字节
-- BYTES(MAX): 最大10,485,760字节

CREATE TABLE files (
    file_id INT64 NOT NULL,
    name STRING(255) NOT NULL,
    content BYTES(MAX),
    thumbnail BYTES(10240)
) PRIMARY KEY (file_id);

-- 插入数据
INSERT INTO files (file_id, name, content)
VALUES (1, 'test.bin', b'\x00\x01\x02\x03');

-- 字节字面量
SELECT b'Hello';               -- 字节字面量
SELECT b'\x48\x65\x6c\x6c\x6f'; -- 十六进制表示

5.2 字节函数 #

sql
-- 字节操作
SELECT LENGTH(b'Hello');       -- 长度: 5
SELECT SUBSTR(b'Hello', 1, 3); -- 子串: b'Hel'

-- 编码转换
SELECT FROM_BASE64('SGVsbG8='); -- Base64解码: b'Hello'
SELECT TO_BASE64(b'Hello');     -- Base64编码: SGVsbG8=
SELECT FROM_HEX('48656C6C6F');  -- 十六进制解码
SELECT TO_HEX(b'Hello');        -- 十六进制编码

-- 字符串与字节转换
SELECT CAST('Hello' AS BYTES);  -- 字符串转字节
SELECT CAST(b'Hello' AS STRING); -- 字节转字符串

六、日期时间类型 #

6.1 DATE #

sql
-- 日期类型,格式: YYYY-MM-DD
-- 范围: 0001-01-01 到 9999-12-31

CREATE TABLE events (
    event_id INT64 NOT NULL,
    event_date DATE NOT NULL,
    end_date DATE
) PRIMARY KEY (event_id);

-- 插入数据
INSERT INTO events (event_id, event_date)
VALUES (1, DATE '2024-01-15');

-- 日期字面量
SELECT DATE '2024-03-27';
SELECT CAST('2024-03-27' AS DATE);

6.2 TIMESTAMP #

sql
-- 时间戳类型,包含日期和时间
-- 精度: 纳秒
-- 时区: UTC

CREATE TABLE logs (
    log_id INT64 NOT NULL,
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP(),
    updated_at TIMESTAMP
) PRIMARY KEY (log_id);

-- 插入数据
INSERT INTO logs (log_id, created_at)
VALUES (1, TIMESTAMP '2024-03-27 10:30:00 UTC');

-- 时间戳字面量
SELECT TIMESTAMP '2024-03-27 10:30:00 UTC';
SELECT TIMESTAMP '2024-03-27 10:30:00+08:00'; -- 带时区

6.3 日期时间函数 #

sql
-- 当前日期时间
SELECT CURRENT_DATE();         -- 当前日期
SELECT CURRENT_TIMESTAMP();    -- 当前时间戳

-- 提取部分
SELECT EXTRACT(YEAR FROM DATE '2024-03-27');    -- 2024
SELECT EXTRACT(MONTH FROM DATE '2024-03-27');   -- 3
SELECT EXTRACT(DAY FROM DATE '2024-03-27');     -- 27
SELECT EXTRACT(DAYOFWEEK FROM DATE '2024-03-27'); -- 4 (周三)

-- 日期运算
SELECT DATE_ADD(DATE '2024-03-27', INTERVAL 1 DAY);    -- 2024-03-28
SELECT DATE_SUB(DATE '2024-03-27', INTERVAL 1 MONTH);  -- 2024-02-27
SELECT DATE_DIFF(DATE '2024-03-27', DATE '2024-03-01', DAY); -- 26

-- 时间戳运算
SELECT TIMESTAMP_ADD(TIMESTAMP '2024-03-27 10:00:00 UTC', INTERVAL 1 HOUR);
SELECT TIMESTAMP_SUB(TIMESTAMP '2024-03-27 10:00:00 UTC', INTERVAL 30 MINUTE);
SELECT TIMESTAMP_DIFF(
    TIMESTAMP '2024-03-27 12:00:00 UTC',
    TIMESTAMP '2024-03-27 10:00:00 UTC',
    HOUR
); -- 2

-- 格式化
SELECT FORMAT_DATE('%Y-%m-%d', DATE '2024-03-27');
SELECT FORMAT_TIMESTAMP('%Y-%m-%d %H:%M:%S', TIMESTAMP '2024-03-27 10:30:00 UTC');

-- 解析
SELECT PARSE_DATE('%Y-%m-%d', '2024-03-27');
SELECT PARSE_TIMESTAMP('%Y-%m-%d %H:%M:%S', '2024-03-27 10:30:00');

七、JSON类型 #

7.1 JSON #

sql
-- JSON类型,存储JSON格式数据
-- 最大大小: 10MB

CREATE TABLE documents (
    doc_id INT64 NOT NULL,
    data JSON NOT NULL,
    metadata JSON
) PRIMARY KEY (doc_id);

-- 插入数据
INSERT INTO documents (doc_id, data)
VALUES (1, JSON '{"name": "John", "age": 30}');

INSERT INTO documents (doc_id, data)
VALUES (2, JSON '{
    "name": "Jane",
    "address": {
        "city": "New York",
        "zip": "10001"
    },
    "tags": ["developer", "manager"]
}');

-- JSON字面量
SELECT JSON '{"key": "value"}';
SELECT CAST('{"key": "value"}' AS JSON);

7.2 JSON函数 #

sql
-- 提取值
SELECT JSON_VALUE(data, '$.name') FROM documents;      -- 提取为字符串
SELECT JSON_QUERY(data, '$.name') FROM documents;      -- 提取为JSON

-- 提取嵌套值
SELECT JSON_VALUE(data, '$.address.city') FROM documents;
SELECT JSON_QUERY(data, '$.address') FROM documents;

-- 提取数组元素
SELECT JSON_VALUE(data, '$.tags[0]') FROM documents;   -- 第一个元素

-- 类型转换
SELECT CAST(JSON '123' AS INT64);      -- JSON转整数
SELECT CAST(JSON '"hello"' AS STRING); -- JSON转字符串

-- JSON构建
SELECT JSON_OBJECT('name', 'John', 'age', 30);
-- {"name":"John","age":30}

SELECT JSON_ARRAY('a', 'b', 'c');
-- ["a","b","c"]

-- JSON修改
SELECT JSON_SET(JSON '{"a":1}', '$.b', 2);
-- {"a":1,"b":2}

SELECT JSON_REMOVE(JSON '{"a":1,"b":2}', '$.a');
-- {"b":2}

-- JSON数组操作
SELECT JSON_ARRAY_LENGTH(JSON '[1, 2, 3]'); -- 3

八、数组类型 #

8.1 ARRAY #

sql
-- 数组类型,存储相同类型的元素
-- 元素必须是标量类型

CREATE TABLE posts (
    post_id INT64 NOT NULL,
    title STRING(200) NOT NULL,
    tags ARRAY<STRING(MAX)>,
    scores ARRAY<INT64>
) PRIMARY KEY (post_id);

-- 插入数据
INSERT INTO posts (post_id, title, tags, scores)
VALUES (1, 'First Post', ['tech', 'spanner', 'database'], [1, 2, 3, 4, 5]);

INSERT INTO posts (post_id, title, tags)
VALUES (2, 'Second Post', ARRAY<STRING(MAX)>[]); -- 空数组

8.2 数组函数 #

sql
-- 数组长度
SELECT ARRAY_LENGTH([1, 2, 3]); -- 3

-- 访问元素(从1开始)
SELECT tags[OFFSET(0)] FROM posts; -- 第一个元素
SELECT tags[ORDINAL(1)] FROM posts; -- 第一个元素(ORDINAL从1开始)

-- 数组操作
SELECT ARRAY_CONCAT([1, 2], [3, 4]); -- [1, 2, 3, 4]
SELECT ARRAY_TO_STRING(['a', 'b', 'c'], ','); -- 'a,b,c'
SELECT STRING_TO_ARRAY('a,b,c', ','); -- ['a', 'b', 'c']

-- 数组聚合
SELECT ARRAY_AGG(name) FROM users; -- 将多行聚合成数组

-- 数组查询
SELECT * FROM posts WHERE 'tech' IN UNNEST(tags);

-- UNNEST展开
SELECT post_id, tag
FROM posts, UNNEST(tags) AS tag;

-- 数组函数
SELECT ARRAY(
    SELECT x * 2 FROM UNNEST([1, 2, 3]) AS x
); -- [2, 4, 6]

-- 数组排序
SELECT ARRAY(
    SELECT x FROM UNNEST([3, 1, 2]) AS x ORDER BY x
); -- [1, 2, 3]

九、结构体类型 #

9.1 STRUCT #

sql
-- 结构体类型,存储命名字段集合
-- 常用于查询结果和嵌套数据

-- 创建结构体
SELECT STRUCT('John' AS name, 30 AS age);
-- {name: 'John', age: 30}

-- 结构体数组
SELECT ARRAY(
    SELECT AS STRUCT name, age FROM users
);

-- 在表中使用结构体
CREATE TABLE orders (
    order_id INT64 NOT NULL,
    customer STRUCT<id INT64, name STRING(100)>,
    items ARRAY<STRUCT<
        product_id INT64,
        quantity INT64,
        price FLOAT64
    >>
) PRIMARY KEY (order_id);

-- 插入数据
INSERT INTO orders (order_id, customer, items)
VALUES (
    1,
    STRUCT<id INT64, name STRING(100)>(1, 'John'),
    [
        STRUCT<product_id INT64, quantity INT64, price FLOAT64>(101, 2, 9.99),
        STRUCT<product_id INT64, quantity INT64, price FLOAT64>(102, 1, 19.99)
    ]
);

9.2 结构体访问 #

sql
-- 访问结构体字段
SELECT customer.name FROM orders WHERE order_id = 1;

-- 展开结构体数组
SELECT 
    order_id,
    item.product_id,
    item.quantity,
    item.price
FROM orders, UNNEST(items) AS item;

十、类型转换 #

10.1 CAST #

sql
-- 显式类型转换
SELECT CAST('123' AS INT64);
SELECT CAST(123 AS STRING);
SELECT CAST('2024-03-27' AS DATE);
SELECT CAST(3.14 AS INT64);    -- 截断为3

-- 转换失败会报错
SELECT CAST('abc' AS INT64);   -- ERROR

10.2 SAFE_CAST #

sql
-- 安全转换,失败返回NULL
SELECT SAFE_CAST('abc' AS INT64);  -- NULL
SELECT SAFE_CAST('123' AS INT64);  -- 123

-- 配合COALESCE使用
SELECT COALESCE(SAFE_CAST('abc' AS INT64), 0); -- 0

10.3 类型转换规则 #

源类型 目标类型 说明
INT64 FLOAT64 精确转换
FLOAT64 INT64 截断小数
STRING INT64 解析数字
STRING DATE 解析日期
STRING TIMESTAMP 解析时间戳
BYTES STRING 解码字节

十一、NULL处理 #

11.1 NULL概念 #

sql
-- NULL表示缺失或未知值
SELECT NULL;
SELECT NULL::INT64;

-- NULL与任何值运算结果为NULL
SELECT NULL + 1;               -- NULL
SELECT NULL = NULL;            -- NULL
SELECT NULL != 1;              -- NULL

11.2 NULL函数 #

sql
-- COALESCE: 返回第一个非NULL值
SELECT COALESCE(NULL, NULL, 'default'); -- 'default'

-- IFNULL: 如果为NULL则返回默认值
SELECT IFNULL(name, 'Unknown') FROM users;

-- NULLIF: 如果相等则返回NULL
SELECT NULLIF(status, 'inactive'); -- 如果status='inactive'返回NULL

-- IS NULL / IS NOT NULL
SELECT * FROM users WHERE email IS NULL;
SELECT * FROM users WHERE email IS NOT NULL;

十二、总结 #

数据类型选择指南:

场景 推荐类型
主键ID INT64
金额 FLOAT64 或 INT64(分)
标志位 BOOL
文本内容 STRING(n) 或 STRING(MAX)
二进制数据 BYTES(MAX)
日期 DATE
时间戳 TIMESTAMP
配置数据 JSON
标签列表 ARRAY
嵌套数据 STRUCT

最佳实践:

text
1. 选择合适的类型
   └── 避免使用STRING(MAX)存储固定长度数据

2. 合理设置长度
   └── STRING(n)比STRING(MAX)更高效

3. 使用ARRAY存储列表
   └── 避免创建关联表

4. 使用JSON存储灵活数据
   └── 不确定Schema时使用

5. 处理NULL值
   └── 使用COALESCE或IFNULL提供默认值

下一步,让我们学习数据库操作!

最后更新:2026-03-27