如何使用bq load加载时将微秒整数转换为BigQuery时间戳
报错根因
BigQuery加载CSV数据时,若整数值要映射到TIMESTAMP类型字段,默认会将整数按秒级Unix epoch时间解析。你传入的是16位微秒级时间戳(比如示例值1611705599779000),按秒换算对应的时间是公元5万多年,远超出TIMESTAMP支持的1年-9999年范围,自然触发越界错误。
bq load本身没有提供参数可以在加载阶段直接指定epoch时间戳的精度(毫秒/微秒/纳秒),没法一步直接把CSV里的微秒整数转成TIMESTAMP落地,但也不是必须走临时表中转,有几种成熟的实现方式:
实现方案
方案1:单表加载后直接改字段类型(无临时表)
- 先把目标分区表的时间字段类型定义为
INT64整数型,正常执行加载命令即可,记得补上--source_format=CSV参数消掉格式警告:
这一步微秒时间戳会原样以整数形式存入表中,不会有解析错误。bq load --skip_leading_rows=1 --source_format=CSV project1.partition_table "gs://data.csv.gz" ./schema.json - 数据加载完成后,执行一条DDL直接把整数字段转为TIMESTAMP类型,转换时用
TIMESTAMP_MICROS函数适配单位:
转换完成后该字段就是原生TIMESTAMP类型,基于该字段的分区规则会自动适配,不需要额外调整。ALTER TABLE project1.partition_table ALTER COLUMN timestamp SET DATA TYPE TIMESTAMP OPTIONS ( conversion_expression = 'TIMESTAMP_MICROS(timestamp)' );
方案2:读取时直接转换写入(无额外临时存储)
不用提前建表,直接用bq query执行读存一体语句,从GCS读取CSV时就完成时间戳转换,直接写入目标分区表,一步到位:
bq query --use_legacy_sql=false \ "CREATE OR REPLACE TABLE project1.partition_table PARTITION BY DATE(timestamp) AS SELECT * EXCEPT(timestamp), TIMESTAMP_MICROS(CAST(timestamp AS INT64)) AS timestamp FROM read_csv( 'gs://data.csv.gz', skip_leading_rows => 1 )"
这种方式不需要提前定义schema,也不会产生临时表的额外存储成本,转换逻辑在数据读取阶段就完成,效率更高。
方案3:临时表中转(兼容旧版本环境)
如果使用的BigQuery版本较旧,不支持ALTER COLUMN自定义转换表达式、也没有read_csv内置函数,再走临时表流程:
- 先把CSV加载到临时表,时间字段按INT64类型存储
- 执行INSERT SELECT语句,用
TIMESTAMP_MICROS把整数转成TIMESTAMP类型写入正式分区表 - 校验数据无误后删除临时表即可
补充说明
如果后续遇到毫秒级时间戳,把上述语句里的TIMESTAMP_MICROS替换为TIMESTAMP_MILLIS即可,纳秒级时间戳对应使用TIMESTAMP_NANOS。不要提前把时间戳转成字符串格式的时间再加载,很容易因为时区、格式匹配问题触发解析错误,性能也不如整数直接转换。
内容的提问来源于stack exchange,提问作者user3605780
相关产品推荐
相关产品推荐

