指定默认列值

本页面介绍如何为 BigQuery 表中的列设置默认值。如果表中某一列包含默认值,但您向该表新添的行不含该列的数据,那么系统会将默认值写入该列。

默认值表达式

列的默认值表达式必须是一个字面量或者是以下一种函数:

您可以使用这些函数(例如 [CURRENT_DATE(), DATE '2020-01-01'])编写 STRUCT 或 ARRAY 默认值。

数据写入表后,系统会对函数进行求值。默认值的类型必须与其对应列的类型一致,否则必须进行强制转换。如果未设置默认值,则默认值为 NULL

设置默认值

您可以在创建新表时设置列的默认值。您可以使用 CREATE TABLE DDL 语句,并在列名称和类型后添加 DEFAULT 关键字和默认值表达式。以下示例会创建一个名为 simple_table 的表,其中包含两个 STRING 列:abb 列的默认值为 'hello'

CREATE TABLE mydataset.simple_table (
  a STRING,
  b STRING DEFAULT 'hello');

如果您将省略了 b 列的数据插入到 simple_table,则系统会使用默认值 'hello',例如:

INSERT mydataset.simple_table (a) VALUES ('val1'), ('val2');

simple_table 表会包含以下值:

+------+-------+
| a    | b     |
+------+-------+
| val1 | hello |
| val2 | hello |
+------+-------+

如果列的类型为 STRUCT,则必须为整个 STRUCT 字段设置默认值;不能只为部分字段设置默认值。数组的默认值不能为 NULL,也不能包含任何 NULL 元素。以下示例会创建一个名为 complex_table 的表,并为 struct_col 列(包含嵌套字段,包括 ARRAY 类型)设置默认值:

CREATE TABLE mydataset.complex_table (
  struct_col STRUCT<x STRUCT<x1 TIMESTAMP, x2 NUMERIC>, y ARRAY<DATE>>
    DEFAULT ((CURRENT_TIMESTAMP(), NULL),
             [DATE '2022-01-01', CURRENT_DATE()])
);

您无法设置违反列限制条件的默认值,例如不符合参数化类型的默认值或列模式REQUIRED 时的 NULL 默认值。

更改默认值

如需更改列的默认值,请选择以下选项之一:

控制台

  1. 在 Google Cloud 控制台中,转到 BigQuery 页面。

    转到 BigQuery

  2. 探索器面板中,展开您的项目和数据集,然后选择表。

  3. 在详细信息面板中,点击架构标签页。

  4. 点击修改架构。您可能需要滚动才能看到此按钮。

  5. 当前架构页面中,找到您要更改的顶级字段。

  6. 输入该字段的默认值。

  7. 点击保存

SQL

使用 ALTER COLUMN SET DEFAULT DDL 语句.

  1. 在 Google Cloud 控制台中,转到 BigQuery 页面。

    转到 BigQuery

  2. 在查询编辑器中,输入以下语句:

    ALTER TABLE mydataset.mytable
    ALTER COLUMN column_name SET DEFAULT default_expression;

  3. 点击 运行

如需详细了解如何运行查询,请参阅运行交互式查询

为列设置的默认值只会影响后续插入到表中的数据;而不会更改任何现有表数据。以下示例会将 a 列的默认值设置为 SESSION_USER()

ALTER TABLE mydataset.simple_table ALTER COLUMN a SET DEFAULT SESSION_USER();

如果您将省略了 a 列的一行数据插入到 simple_table 中,则系统会使用当前会话用户。

INSERT mydataset.simple_table (b) VALUES ('goodbye');

simple_table 表会包含以下值:

+------------------+---------+
| a                | b       |
+------------------+---------+
| val1             | hello   |
| val2             | hello   |
| user@example.com | goodbye |
+------------------+---------+

移除默认值

如需移除列的默认值,请选择以下选项之一:

控制台

  1. 在 Google Cloud 控制台中,转到 BigQuery 页面。

    转到 BigQuery

  2. 探索器面板中,展开您的项目和数据集,然后选择表。

  3. 在详细信息面板中,点击架构标签页。

  4. 点击修改架构。您可能需要滚动才能看到此按钮。

  5. 当前架构页面中,找到您要更改的顶级字段。

  6. 输入 NULL 以作为默认值。

  7. 点击保存

SQL

使用 ALTER COLUMN DROP DEFAULT DDL 语句.

  1. 在 Google Cloud 控制台中,转到 BigQuery 页面。

    转到 BigQuery

  2. 在查询编辑器中,输入以下语句:

    ALTER TABLE mydataset.mytable ALTER COLUMN column_name DROP DEFAULT;

    您还可以使用 ALTER COLUMN SET DEFAULT DDL 语句将列的值更改为 NULL,从而从列中移除默认值。

  3. 点击 运行

如需详细了解如何运行查询,请参阅运行交互式查询

使用带有默认值的 DML 语句

您可以使用 INSERT DML 语句将具有默认值的行添加到表中。如果未指定列的值,或使用关键字 DEFAULT 代替值表达式,系统便会使用默认值。以下示例会创建一个表并插入一行数据,其中每个值都是默认值:

CREATE TABLE mydataset.mytable (
  x TIME DEFAULT CURRENT_TIME(),
  y INT64 DEFAULT 5,
  z BOOL);

INSERT mydataset.mytable (x, y, z) VALUES (DEFAULT, DEFAULT, DEFAULT);

mytable 表如下所示:

+-----------------+---+------+
| x               | y | z    |
+-----------------+---+------+
| 22:13:24.799555 | 5 | null |
+-----------------+---+------+

由于 z 列没有默认值,因此系统会使用 NULL 作为默认值。如果默认值是一个函数(例如 CURRENT_TIME()),系统会在写入值时对该函数进行求值。再次调用包含 x 列默认值的 INSERT 时,系统会生成一个不同的 TIME 值。在以下示例中,只有 z 列明确设置了值,并且省略的列均使用其默认值:

INSERT mydataset.mytable (z) VALUES (TRUE);

mytable 表如下所示:

+-----------------+---+------+
| x               | y | z    |
+-----------------+---+------+
| 22:13:24.799555 | 5 | null |
| 22:18:29.890547 | 5 | true |
+-----------------+---+------+

您可以使用 MERGE DML 语句用默认值更新表。以下示例会创建两个表并使用 MERGE 语句更新其中一个表:

CREATE TABLE mydataset.target_table (
  a STRING,
  b STRING DEFAULT 'default_b',
  c STRING DEFAULT SESSION_USER())
AS (
  SELECT
    'val1' AS a, 'hi' AS b, '123@google.com' AS c
  UNION ALL
  SELECT
    'val2' AS a, 'goodbye' AS b, SESSION_USER() AS c
);

CREATE TABLE mydataset.source_table (
  a STRING DEFAULT 'default_val',
  b STRING DEFAULT 'Happy day!')
AS (
  SELECT
    'val1' AS a, 'Good evening!' AS b
  UNION ALL
  SELECT
    'val3' AS a, 'Good morning!' AS b
);

MERGE mydataset.target_table T
USING mydataset.source_table S
ON T.a = S.a
WHEN NOT MATCHED THEN
  INSERT(a, b) VALUES (a, DEFAULT);

结果如下:

+------+-----------+--------------------+
| a    | b         | c                  |
+------+-----------+--------------------+
| val1 | hi        | 123@google.com     |
| val2 | goodbye   | default@google.com |
| val3 | default_b | default@google.com |
+------+-----------+--------------------+

您可以使用 UPDATE DML 语句用默认值更新表。以下示例会更新 source_table 表,使每一行 b 列的值都等于其默认值:

UPDATE mydataset.source_table
SET b =  DEFAULT
WHERE TRUE;

结果如下:

+------+------------+
| a    | b          |
+------+------------+
| val1 | Happy day! |
| val3 | Happy day! |
+------+------------+

附加表

您可以将 bq query 命令与 --append_table 标志结合使用,将查询结果附加到具有默认值的目标表。如果查询省略了具有默认值的列,系统会分配默认值。以下示例会附加仅指定 z 列值的数据:

bq query \
    --nouse_legacy_sql \
    --append_table \
    --destination_table=mydataset.mytable \
    'SELECT FALSE AS z UNION ALL SELECT FALSE AS Z'

mytable 表会使用 xy 列的默认值:

+-----------------+---+-------+
|        x        | y |   z   |
+-----------------+---+-------+
| 22:13:24.799555 | 5 |  NULL |
| 22:18:29.890547 | 5 |  true |
| 23:05:18.841683 | 5 | false |
| 23:05:18.841683 | 5 | false |
+-----------------+---+-------+

加载数据

您可以使用 bq load 命令LOAD DATA 语句将数据加载到具有默认值的表中。如果所加载数据包含的列数少于目标表中的列数,系统便会应用默认值。所加载数据中的 NULL 值不会被转换为默认值。

二进制格式(如 AVRO、Parquet 或 ORC)包含编码文件架构。如果文件架构省略了某些列,则系统会应用默认值。

文本格式(如 JSON 和 CSV)不含编码文件架构。如需使用 bq 命令行工具指定其架构,您可以使用 --autodetect 标志或提供 JSON 架构。如需使用 LOAD DATA 语句指定其架构,您必须提供包含各列的列表。以下示例演示了如何仅从 CSV 文件加载 a 列:

LOAD DATA INTO mydataset.insert_table (a)
FROM FILES(
  uris = ['gs://test-bucket/sample.csv'],
  format = 'CSV');

Write API

仅当写入流架构缺少目标表架构中包含的字段时,Storage Write API 才会填充默认值。在这种情况下,每次写入时,缺少的字段都会填充列中的默认值。如果写入流架构中存在该字段,但数据本身缺少该字段,则缺少的字段会填充 NULL。例如,假设您要使用以下架构将数据写入 BigQuery 表:

[
  {
    "name": "a",
    "mode": "NULLABLE",
    "type": "STRING",
  },
  {
    "name": "b",
    "mode": "NULLABLE",
    "type": "STRING",
    "defaultValueExpression": "'default_b'"
  },
  {
    "name": "c",
    "mode": "NULLABLE",
    "type": "STRING",
    "defaultValueExpression": "'default_c'"
  }
]

以下写入流架构缺少目标表中存在的 c 字段:

[
  {
    "name": "a",
    "type": "STRING",
  },
  {
    "name": "b",
    "type": "STRING",
  }
]

现在,假设您将以下值流式传输到表中:

{'a': 'val_a', 'b': 'val_b'}
{'a': 'val_a'}

结果如下:

+-------+-------+-----------+
| a     | b     | c         |
+-------+-------+-----------+
| val_a | val_b | default_c |
| val_a | NULL  | default_c |
+-------+-------+-----------+

写入流架构包含字段 b,因此即使没有为该字段指定值,系统也不会使用默认值 default_b。由于写入流架构不包含 c 字段,因此 c 列的每一行都填充了目标表的默认值 default_c

以下写入流架构与您要写入的表的架构一致:

[
  {
    "name": "a",
    "type": "STRING",
  },
  {
    "name": "b",
    "type": "STRING",
  }
  {
    "name": "c",
    "type": "STRING",
  }
]

现在,假设您将以下值流式传输到表中:

{'a': 'val_a', 'b': 'val_b'}
{'a': 'val_a'}

写入流架构不会缺少目标表中包含的任何字段,因此无论流式数据中是否填充了字段,系统都不会应用列的任何默认值:

+-------+-------+------+
| a     | b     | c    |
+-------+-------+------+
| val_a | val_b | NULL |
| val_a | NULL  | NULL |
+-------+-------+------+

您可以在 AppendRowsRequest 消息default_missing_value_interpretation 中指定连接级默认值设置。如果该值设置为 DEFAULT_VALUE,则即使列出现在用户架构中,缺失值也会获取默认值。

您还可以在 AppendRowsRequest 消息内的 missing_value_interpretations 映射中指定请求级默认值。每个键都是列的名称,其表示如何解释缺失值。

例如,映射 {'col1': NULL_VALUE, 'col2': DEFAULT_VALUE} 表示 col1 中的所有缺失值都会被解释为 NULLcol2 中的所有缺失值都会被解释为表架构中针对 col2 设置的默认值。

如果某个字段不在该映射中且缺少值,则缺失的值会被解释为 NULL

键只能是顶级列名称。键不能是结构体子字段,例如 col1.subfield1

使用 insertAll API 方法

将数据写入表时,tabledata.insertAll API 方法会在行级填充默认值。如果某行缺少具有默认值的列,则系统会为这些列应用默认值。

例如,假设表架构如下所示:

[
  {
    "name": "a",
    "mode": "NULLABLE",
    "type": "STRING",
  },
  {
    "name": "b",
    "mode": "NULLABLE",
    "type": "STRING",
    "defaultValueExpression": "'default_b'"
  },
  {
    "name": "c",
    "mode": "NULLABLE",
    "type": "STRING",
    "defaultValueExpression": "'default_c'"
  }
]

现在,假设您将以下值流式传输到表中:

{'a': 'val_a', 'b': 'val_b'}
{'a': 'val_a'}
{}

结果如下:

+-------+------------+-----------+
| a     | b          | c         |
+-------+------------+-----------+
| val_a | val_b      | default_c |
| val_a | default_b  | default_c |
| NULL  | default_b  | default_c |
+-------+------------+-----------+

由于插入的第一行不包含字段 c 的值,因此默认值 default_c 被写入到 c 列。由于插入的第二行不包含字段 bc 的值,因此其默认值被写入 bc 列。插入的第三行不包含任何值。由于未设置其他默认值,因此写入 a 列的值是 NULL。默认值 default_bdefault_c 会写入 bc 列。

查看默认值

如需查看列的默认值,请查询 INFORMATION_SCHEMA.COLUMNS 视图column_default 列字段包含列的默认值。如果未设置默认值,则该字段值为 NULL。以下示例展示了 mytable 表的列名和默认值:

SELECT
  column_name,
  column_default
FROM
  mydataset.INFORMATION_SCHEMA.COLUMNS
WHERE
  table_name = 'mytable';

结果类似于以下内容:

+-------------+----------------+
| column_name | column_default |
+-------------+----------------+
| x           | CURRENT_TIME() |
| y           | 5              |
| z           | NULL           |
+-------------+----------------+

限制

  • 您可以使用旧版 SQL 从具有默认值的表中读取数据,但无法使用旧版 SQL 将数据写入到具有默认值的表中。
  • 您无法向现有表添加具有默认值的新列。但是,您可以添加不含默认值的列,然后使用 ALTER COLUMN SET DEFAULT DDL 语句更改其默认值。
  • 您无法将源表复制和附加到所含列数比源表列数多且那些多出来的列包含默认值的目标表。您可以运行 INSERT destination_table SELECT * FROM source_table 来复制数据。

后续步骤

  • 如需详细了解如何将数据加载到 BigQuery 中,请参阅加载数据简介