CSV/TSV/纯TEXTFILE外部表

本文为您介绍CSV、TSV、纯TEXTFILE格式的OSS外部表的创建、读取及写入方法。

前提条件

  • 已具备访问OSS的权限。阿里云账号(主账号)、RAM用户或RAMRole身份可以访问OSS外部表,授权信息请参见OSSSTS模式授权

  • (可选)已准备好OSS存储空间(Bucket)、OSS目录及OSS数据文件。具体操作请参见创建存储空间管理目录简单上传

    MaxCompute已支持在OSS侧自动创建目录,对于携带外部表及UDFSQL语句,您可以通过一条SQL语句执行读写外部表及UDF的操作。原手动创建目录方式仍然支持。
  • 已创建MaxCompute项目。具体操作请参见创建MaxCompute项目

    由于MaxCompute只在部分地域部署,跨地域的数据连通性可能存在问题,因此建议BucketMaxCompute项目所在地域保持一致。
  • 已具备在MaxCompute项目中创建表(CreateTable)的权限。表操作的权限信息请参见MaxCompute权限

使用限制

  • OSS外部表不支持cluster属性。

  • 单个文件大小不能超过3 GB,如果文件过大,建议拆分。

数据类型支持

说明

下表中已开通表示支持,未开通表示不支持。

数据类型

com.aliyun.odps.CsvStorageHandler

(内置文本数据解析器)

org.apache.hadoop.hive.serde2.OpenCSVSerde

(内置开源数据解析器)

TINYINT

已开通

已开通

SMALLINT

已开通

已开通

INT

已开通

已开通

BIGINT

已开通

已开通

BINARY

未开通

未开通

FLOAT

已开通

已开通

DOUBLE

已开通

已开通

DECIMAL(precision,scale)

已开通

已开通

VARCHAR(n)

已开通

已开通

CHAR(n)

已开通

已开通

STRING

已开通

已开通

DATE

已开通

已开通

DATETIME

已开通

已开通

TIMESTAMP

已开通

已开通

TIMESTAMP_NTZ

已开通

未开通

BOOLEAN

已开通

已开通

ARRAY

未开通

未开通

MAP

未开通

未开通

STRUCT

未开通

未开通

JSON

未开通

未开通

压缩格式支持

当您需要读写压缩属性的OSS文件时,需要在建表语句中添加with serdeproperties属性配置,详情请参见with serdeproperties属性参数

压缩格式

com.aliyun.odps.CsvStorageHandler

(内置文本数据解析器)

org.apache.hadoop.hive.serde2.OpenCSVSerde

(内置开源数据解析器)

GZIP

已开通

已开通

SNAPPY

未开通

已开通

LZO

未开通

已开通

创建外部表

语法结构

各格式的外部表语法结构详情,请参见OSS外部表

  • 内置文本数据解析器

    CSV格式

    CREATE EXTERNAL TABLE [IF NOT EXISTS] <mc_oss_extable_name> 
    (
      <col_name> <data_type>,
      ...
    )
    [COMMENT <table_comment>]
    [PARTITIONED BY (<col_name> <data_type>, ...)] 
    STORED BY 'com.aliyun.odps.CsvStorageHandler'  
    [WITH serdeproperties (
      ['<property_name>'='<property_value>',...]
    )] 
    LOCATION '<oss_location>'
    [tblproperties ('<tbproperty_name>'='<tbproperty_value>',...)];

    TSV格式

    CREATE EXTERNAL TABLE [IF NOT EXISTS] <mc_oss_extable_name> 
    (
      <col_name> <data_type>,
      ...
    )
    [COMMENT <table_comment>]
    [PARTITIONED BY (<col_name> <data_type>, ...)] 
    STORED BY 'com.aliyun.odps.TsvStorageHandler'  
    [WITH serdeproperties (
      ['<property_name>'='<property_value>',...]
    )] 
    LOCATION '<oss_location>'
    [tblproperties ('<tbproperty_name>'='<tbproperty_value>',...)];
  • 内置开源数据解析器

    CREATE EXTERNAL TABLE [IF NOT EXISTS] <mc_oss_extable_name>
    (
      <col_name> <data_type>,
      ...
    )
    [COMMENT <table_comment>]
    [PARTITIONED BY (<col_name> <data_type>, ...)]
    ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.OpenCSVSerde'
    [WITH serdeproperties (
      ['<property_name>'='<property_value>',...]
    )]
    STORED AS TEXTFILE 
    LOCATION '<oss_location>' 
    [tblproperties ('<tbproperty_name>'='<tbproperty_value>',...)];

公共参数

公共参数说明请参见基础语法参数说明

独有参数

with serdeproperties属性参数

property_name

使用场景

说明

property_value

默认值

odps.text.option.gzip.input.enabled

当需要读取以GZIP方式压缩的CSVTSV文件数据时,请添加该属性。

CSV、TSV压缩属性。配置该参数值为True时,MaxCompute才可以正常读取压缩文件,否则会读取失败。

  • True

  • False

False

odps.text.option.gzip.output.enabled

当需要将数据以GZIP压缩方式写入OSS时,请添加该属性。

CSV、TSV压缩属性。配置该参数值为True时,MaxCompute才能将数据以GZIP压缩方式写入OSS,否则不压缩。

  • True

  • False

False

odps.text.option.header.lines.count

OSS数据文件为CSVTSV,且需要忽略OSS数据文件中的前N行时,请添加该属性。

MaxCompute读取OSS数据文件时,会忽略指定的行数。

非负整数

0

odps.text.option.null.indicator

OSS数据文件为CSVTSV,且需要定义OSS数据文件中NULL的解析规则时,请添加该属性。

通过该参数配置的字符串会被解析为SQL中的NULL。例如\N指代NULL,则a,\N,b会解析为a, NULL, b

字符串

空字符串

odps.text.option.ignore.empty.lines

OSS数据文件为CSVTSV,且需要定义OSS数据文件中空行的处理规则时,请添加该属性。

配置该参数值为True时,MaxCompute会忽略数据文件中的空行,否则会读取空行。

  • True

  • False

True

odps.text.option.encoding

OSS数据文件为CSVTSV,且OSS数据文件编码规则非默认编码规则时,请添加该属性。

确保此处配置的编码规则与OSS数据文件编码规则保持一致,否则MaxCompute无法成功读取数据。

  • UTF-8

  • UTF-16

  • US-ASCII

  • GBK

UTF-8

odps.text.option.delimiter

当需要明确CSVTSV数据文件的列分隔符时,请添加该属性。

确保此处配置的列分隔符可以正确读取OSS数据文件的每一列,否则MaxCompute读取的数据会出现错位问题。

单个字符

半角逗号(,)

odps.text.option.use.quote

CSVTSV数据文件中的字段包含换行(CRLF)、双引号或英文逗号时,请添加该属性。

CSV某个字段中包含换行、双引号(需要在"前再加"转义)或英文逗号时,整个字段必须用双引号("")括起来作为列分隔符。该参数指定是否识别CSV的列分隔符"

  • True

  • False

False

separatorChar

当需要明确以TEXTFILE格式保存的CSV数据的列分隔符时,请添加该属性。

指定CSV数据列分隔符。

单个字符串

半角逗号(,)

quoteChar

当以TEXTFILE格式保存的CSV数据中的字段包含换行、双引号或英文逗号时,请添加该属性。

指定CSV数据的引用符。

单个字符串

escapeChar

当需要明确以TEXTFILE格式保存的CSV数据的转义规则时,请添加该属性。

指定CSV数据的转义符。

单个字符串

odps.sql.text.option.flush.header

在往OSS写数据的时候,文件块的第一行为表头。

只有针对CSV文件格式生效。

  • True

  • False

False

odps.sql.text.schema.mismatch.mode

当读取的OSS文件的数据列数和外部表的Schema列数不一致时。

指定对于列数不一致行的处理方式。

说明:odps.text.option.use.quote参数值为True时,该功能不生效。

  • error:报错。

  • truncate:超过外部表列数部分数据被截断;少于外部表列数部分数据则补null

  • ignore:丢弃不一致的行。

error

tblproperties属性参数

property_name

使用场景

说明

property_value

默认值

skip.header.line.count

当需要忽略以TEXTFILE格式保存的CSV文件中的前N行数据时,请添加该属性。

MaxCompute读取OSS数据时,会忽略从首行开始指定行数的数据。

非负整数

skip.footer.line.count

当需要忽略以TEXTFILE格式保存的CSV文件中的后N行数据时,请添加该属性。

MaxCompute读取OSS数据时,会忽略从尾行开始指定行数的数据。

非负整数

mcfed.mapreduce.output.fileoutputformat.compress

当需要将TEXTFILE数据文件以压缩方式写入OSS时,请添加该属性。

TEXTFILE压缩属性。配置该参数值为True时,MaxCompute才可以将TEXTFILE数据文件以压缩方式写入OSS,否则不压缩。

  • True

  • False

False

mcfed.mapreduce.output.fileoutputformat.compress.codec

当需要将TEXTFILE数据文件以压缩方式写入OSS时,请添加该属性。

TEXTFILE压缩属性。设置TEXTFILE数据文件的压缩方式。

说明:只支持property_value中的四种压缩方式。

  • com.hadoop.compression.lzo.LzoCodec

  • com.hadoop.compression.lzo.LzopCodec

  • org.apache.hadoop.io.compress.SnappyCodec

  • com.aliyun.odps.io.compress.SnappyRawCodec

io.compression.codecs

OSS数据文件为Raw-Snappy格式时,请添加该属性。

配置该参数值为True时,MaxCompute才可以正常读取压缩数据,否则MaxCompute无法成功读取数据。

com.aliyun.odps.io.compress.SnappyRawCodec

写入数据

MaxCompute写入语法详情,请参见写入语法说明

查询分析

Smart Parse更灵活的类型能力

针对CSV格式的OSS外部表,MaxCompute SQL采用2.0数据类型进行读写,之前仅支持部分严格格式的值,并按照相应的数据类型进行读写。现已兼容读取CSV中各种类型的值。具体如下:

Type

Input as String

Output as String

Description

BOOLEAN

  • "true"/"false"

  • "T"/"F"

  • "1"/"0"

  • "Yes"/"No"

  • "Y"/"N"

  • ""(空串读进表中会被解析为NULL)

说明

解析时会对输入执行trim()操作。

  • "true"/"false"

  • "true"/"false"

  • "true"/"false"

  • "true"/"false"

  • "true"/"false"

  • ""(NULL被输出至CSV中为空串)

不在枚举值范围,则解析失败。

TINYINT

  • "0"

  • "1"

  • "-100"

  • "1,234,567"(千分位表示法,逗号不能作为该数字串的首尾字符)

  • "1_234_567"(Java-style,下划线不能作为该数字串的首尾字符)

  • "0.3e2"(科学计数法,其表示的实际数值为整数时可被解析,否则会报错)

  • "-1e5"(科学计数法)

  • "0xff"(十六进制,大小写不敏感)

  • "0b1001"(二进制,大小写不敏感)

  • "4/2"(分数,其表示的实际数值为整数时可被解析,否则会报错)

  • "1000%"(百分数,其表示的实际数值为整数时可被解析,否则会报错)

  • "1000‰"(千分数,其表示的实际数值为整数时可被解析,否则会报错)

  • "1,000 $"(带货币符号)

  • "$ 1,000"(带货币符号)

  • "3M"(K8s-style, 1000进制单位)

  • "2Gi"(K8s-style, 1024进制单位)

  • ""(空串读进表中会被解析为NULL)

说明
  • 解析时会对输入执行trim()操作。

  • 如果使用千分位表示法,例如"1,234,567" ,则需要手动设置CSV分隔符为非英文逗号的其他符号。具体请参见with serdeproperties属性参数odps.text.option.delimiter的用法。

  • K8s-style支持的1000进制单位包括 K/M/G/P/T,1024进制单位包括 Ki/Mi/Gi/Pi/Ti,详情请参见resource-management

  • 货币符号包括$/¥/€/£/₩/USD/CNY/EUR/GBP/JPY/KRW/IDR/RP

  • "0""1""-100"""naive模式下也可以被正确解析。

  • "0"

  • "1"

  • "-100"

  • "1234567"

  • "1234567"

  • "30"

  • "-100000"

  • "255"

  • "9"

  • "2"

  • "10"

  • "1"

  • "1000"

  • "1000"

  • "3000000"(1M=1000*1000)

  • "2147483648"(1 Gi=1024*1024*1024)

  • ""(NULL被输出至CSV中为空串)

8位整型,超出值域范围[-128, 127]则报错。

SMALLINT

16位整型,超出值域范围[-32768, 32767]则报错。

INT

32位整型,超出值域范围[-2147483648, 2147483647]则报错。

BIGINT

64位整型,超出值域范围[-9223372036854775807, 9223372036854775807]则报错。

说明

-263(即-9223372036854775808)不在值域范围内,为SQL引擎的限制。

FLOAT

  • "3.14"

  • "0.314e1"(科学计数法)

  • "2/5"(分数)

  • "123.45%"(百分数)

  • "123.45‰"(千分数)

  • "1,234,567.89"(千分位表示)

  • "1,234.56 $"(带货币符号)

  • "$ 1,234.56"(带货币符号)

  • "1.2M"(K8s-style,1000进制单位)

  • "2Gi"(K8s-style,1024进制单位)

  • "NaN"(大小写不敏感)

  • "Inf"(大小写不敏感)

  • "-Inf"(大小写不敏感)

  • "Infinity"(大小写不敏感)

  • "-Infinity"(大小写不敏感)

  • ""(空串读进表中会被解析为NULL)

说明
  • 解析时会对输入执行trim()操作。

  • "3.14""0.314e1""NaN""Infinity""-Infinity"""naive模式下也可以被正确解析。

  • "3.14"

  • "3.14"

  • "0.4"

  • "1.2345"

  • "0.12345"

  • "1234567.89"

  • "1234.56"

  • "1234.56"

  • "1200000"

  • "2147483648"

  • "NaN"

  • "Infinity"

  • "-Infinity"

  • "Infinity"

  • "-Infinity"

  • ""(null被输出至csv中为空串)

特殊值(大小写不敏感)包括:NaN、Inf、-Inf、Intifniy和-Intifniy。在超出值域范围时,将报错;若精度超出,则进行四舍五入截断。

DOUBLE

  • "3.1415926"

  • "0.314e1"(科学计数法)

  • "2/5"(分数)

  • "123.45%"(百分数)

  • "123.45‰"(千分数)

  • "1,234,567.89"(千分位表示)

  • "1,234.56 $"(带货币符号)

  • "$ 1,234.56"(带货币符号)

  • "1.2M"(K8s-style,1000进制单位)

  • "2Gi"(K8s-style,1024进制单位)

  • "NaN"(大小写不敏感)

  • "Inf"(大小写不敏感)

  • "-Inf"(大小写不敏感)

  • "Infinity"(大小写不敏感)

  • "-Infinity"(大小写不敏感)

  • ""(空串读进表中会被解析为NULL)

说明
  • 解析时会对输入执行trim()操作。

  • "3.1415926""0.314e1""NaN""Infinity""-Infinity"""naive模式下也可以被正确解析。

  • "3.1415926"

  • "3.14"

  • "0.4"

  • "1.2345"

  • "0.12345"

  • "1234567.89"

  • "1234.56"

  • "1234.56"

  • "1200000"

  • "2147483648"

  • "NaN"

  • "Infinity"

  • "-Infinity"

  • "Infinity"

  • "-Infinity"

  • ""(NULL被输出至CSV中为空串)

特殊值(大小写不敏感)包括:NaN、Inf、-Inf、Intifniy和-Intifniy。在超出值域范围时,将报错;若精度超出,则进行四舍五入截断。

DECIMAL

(precision, scale)

DECIMAL(15,2)为例

  • "3.358"

  • "2/5"(分数)

  • "123.45%"(百分数)

  • "123.45‰"(千分数)

  • "1,234,567.89"(千分位表示)

  • "1,234.56 $"(带货币符号)

  • "$ 1,234.56"(带货币符号)

  • "1.2M"(K8s-style, 1000进制单位)

  • "2Gi"(K8s-style, 1024进制单位)

  • ""(空串读进表中会被解析为NULL)

说明
  • 解析时会对输入执行trim()操作。

  • "3.358"""naive模式下也可以被正确解析。

  • "3.36"(四舍五入)

  • "0.4"

  • "1.23"(四舍五入)

  • "0.12"(四舍五入)

  • "1234567.89"

  • "1234.56"

  • "1234.56"

  • "1200000"

  • "2147483648"

  • ""(NULL被输出至CSV中为空串)

整数部分值超出precision-scale

则会报错;小数部分超出scale,则会进行四舍五入截断。

CHAR(n)

CHAR(7)为例

  • "abcdefg"

  • "abcdefghijklmn"

  • "abc"

  • ""(空串读进表中会被解析为NULL)

  • "abcdefg"

  • "abcdefg"(后续部分被截断)

  • "abc____"(_表示空格,扩充了4个空字符)

  • ""(NULL被输出至CSV中为空串)

最大长度为255。长度不足则会填充空格,但空格不参与比较。长度超出n会截断。

VARCHAR(n)

VARCHAR(7)为例

  • "abcdefg"

  • "abcdefghijklmn"

  • "abc"

  • ""(空串读进表中会被解析为NULL)

  • "abcdefg"

  • "abcdefg"(后续部分被截断)

  • "abc"

  • ""(NULL被输出至CSV中为空串)

最大长度为65535。长度超出n会截断。

STRING

  • "abcdefg"

  • "abc"

  • ""(空串读进表中会被解析为NULL)

  • "abcdefg"

  • "abc"

  • ""(NULL被输出至CSV中为空串)

长度限制为8 MB。

DATE

  • "yyyy-MM-dd"(例如"2025-02-21")

  • "yyyyMMdd"(例如"20250221")

  • "MMM d,yyyy"(例如"October 1,2025")

  • "MMMM d,yyyy"(例如"Oct 1,2025")

  • "yyyyMd日"(例如"2025101日")

  • ""(空串读进表中会被解析为NULL)

说明

您也可以通过自定义odps.text.option.date.io.format控制读入时的解析方式。例如用户定义format'dd/MM/yyyy#yyyy--MM--dd',则可以解析'21/02/2025''2025--02--21'

  • "2000-01-01"

  • "2000-01-01"

  • ""(NULL被输出至CSV中为空串)

  • 无时分秒信息,改变时区不影响输出结果。默认输出格式为"yyyy-MM-dd"

  • 您也可以通过自定义odps.text.option.date.io.format 来控制解析与输出格式。输出格式将采用自定义的首个pattern。格式可参考DateTimeFormatter

TIMESTAMP_NTZ

说明

OpenCsvSerde不支持此类型,因为该类型与Hive数据格式不兼容。

  • 纳秒位长度可为0~9,MaxCompute支持的内置解析格式如下:

    • "yyyy-MM-dd HH:mm:ss[.SSSSSSSSS]"(例如"2000-01-01 00:00:00.123")

    • "yyyy-MM-ddTHH:mm:ss[.SSSSSSSSS]"(例如"2000-01-01T00:00:00.123456789")

    • "yyyyMMddHHmmss"(例如"20000101000000")

    • ""(空串读进表中会被解析为NULL)

  • 您也可通过自定义odps.text.option.timestamp_ntz.io.format来控制读入时的解析方式。例如用户定义format'ddMMyyyy-HHmmss',则可以解析形如'31102024-103055'的字符串。

  • "2000-01-01 00:00:00.123000000"

  • "2000-01-01 00:00:00.123456789"

  • "2000-01-01 00:00:00.000000000"

  • ""(NULL被输出至CSV中为空串)

  • 本质为纳秒粒度的时间戳,改变时区信息不影响输出结果,即默认使用标准UTC时区输出结果。默认输出格式为"yyyy-MM-dd HH:mm:ss.SSSSSSSSS"

  • 您也可以通过自定义odps.text.option.timestamp_ntz.io.format控制解析与输出格式。格式可参考DateTimeFormatter

DATETIME

  • 毫秒位长度可为0~3,x表示时区偏移,假设系统时区为Asia/Shanghai,MaxCompute支持的内置解析格式如下:

    • "yyyy-MM-dd HH:mm:ss[.SSS][x]"(例如"2000-01-01 00:00:00.123")

    • "yyyy-MM-ddTHH:mm:ss[.SSS][x]"(例如"2000-01-01T00:00:00.123+0000")

    • "yyyyMMddHHmmss[x]" (例如"20000101000000+0000")

    • ""(空串读进表中会被解析为NULL)

  • 您也可通过自定义odps.text.option.datetime.io.format来控制读入时的解析方式。例如用户定义format'yyyyMMdd-HHmmss.SSS',则可以解析形如'20241031-103055.123'的字符串。

假设系统时区为Asia/Shanghai:

  • "2000-01-01 00:00:00.123+0800"

  • "2000-01-01 08:00:00.123+0800"

  • "2000-01-01 08:00:00.000+0800"

  • ""(NULL被输出至CSV中为空串)

  • 本质为毫秒粒度的时间戳,改变时区信息影响输出结果。默认输出格式为"yyyy-MM-dd HH:mm:ss.SSSx"

  • 您可通过odps.sql.timezone修改系统时区,从而控制写出值的时区偏移。

  • 您也可通过自定义odps.text.option.datetime.io.format控制解析与输出格式。格式可参考:DateTimeFormatter

TIMESTAMP

  • 纳秒位长度可为0~9,x表示时区偏移,假设系统时区为Asia/Shanghai,MaxCompute支持的内置解析格式:

    • "yyyy-MM-dd HH:mm:ss[.SSSSSSSSS][x]"(例如"2000-01-01 00:00:00.123456")

    • "yyyy-MM-ddTHH:mm:ss[.SSSSSSSSS][x]"(例如"2000-01-01T00:00:00.123+0000")

    • "yyyyMMddHHmmss[x]"(例如"20000101000000+0000")

    • ""(空串读进表中会被解析为NULL)

  • 您也可通过自定义odps.text.option.timestamp.io.format来控制读入时的解析方式。例如用户定义format'yyyyMMdd-HHmmss',则可以解析形如'20240910-103055'的字符串。

(假设系统时区为Asia/Shanghai)

  • "2000-01-01 00:00:00.123456000+0800"

  • "2000-01-01 08:00:00.123000000+0800"

  • "2000-01-01 08:00:00.000000000+0800"

  • ""(NULL被输出至CSV中为空串)

  • 本质为纳秒粒度的时间戳,改变时区信息影响输出结果。默认输出格式为"yyyy-MM-dd HH:mm:ss.SSSSSSSSSx"

  • 您可通过odps.sql.timezone修改系统时区,从而控制写出值的时区偏移。

  • 您也可通过自定义odps.text.option.timestamp.io.format控制解析与输出格式。格式可参考DateTimeFormatter

注意事项

  • 对于任意类型,CSV数据文件中的空字符串被读入表中后,均会被解析为NULL。

  • 不支持STRUCT/ARRAY/MAP等复杂类型,因为这些复杂类型的值很容易和CSV的常见分隔符(,)发生冲突导致解析失败。

  • 暂不支持BINARY/INTERVAL类型,如有需求请联系MaxCompute技术支持。

  • 对于数据类型INT/SMALLINT/TINYINT/BIGINT/FLOAT/DOUBLE/DECIMAL,默认的解析能力(DEFAULT)比较丰富。

    如果您只想对基础的数字串进行解析,可以在tblproperties中将odps.text.option.smart.parse.level参数设置为naive,使解析器仅支持解析普通数字串,例如“123”、“123.456”,其他形态的字符串在解析时会报错。

  • 对于四种日期或时间相关类型DATA/DATATIME/TIMESTAMP/TIMESTAMP_NTZ,在底层代码中均使用java.time.format.DateTimeFormatter进行处理。MaxCompute内置了若干的默认解析格式,您也可以通过在tblproperties中设置odps.text.option.<date|datetime|timestamp|timestamp_ntz>.io.format来自定义多种解析格式与一种输出格式,解析格式之间用#分隔。

    • 自定义格式的优先级高于MaxCompute的内置解析格式,输出格式将采用第一个自定义格式。

      例如,若您自定义DATE类型的格式串为pattern1#pattern2#pattern3,则可以解析符合pattern1pattern2pattern3的字符串,但输出至文件时会采用pattern1格式来输出。详情请参见DateTimeFormatter

    • 不建议使用 'z' (time-zone name) 作为自定义的时区格式(尤其对于中国区用户),因为 'z' 在某些上下文中可能存在歧义。

      例如:'CST' 在中国语境下通常表示中国标准时间(UTC+8),然而当 'CST' 被java.time.format.DateTimeFormatter解析时,会被识别为美国中部标准时间(UTC-6),这可能导致非预期的输入或输出结果。建议您改用 'x' (zone-offset) 或 'VV' (time-zone ID) 作为时区模式。

使用示例

说明
  • 执行下述示例代码时,请将代码中的<uid>替换为您的阿里云账号ID。

  • 下述示例中使用的角色为aliyunodpsdefaultrole,如果您想使用其他角色,需要将aliyunodpsdefaultrole替换为目标角色名称,并为目标角色授予访问OSS的权限。

通过内置文本数据解析器创建OSS外部表-非分区表

  1. 示例数据中的Demo1/目录建立映射关系。创建OSS外部表的命令示例如下。

    CREATE EXTERNAL TABLE IF NOT EXISTS mc_oss_csv_external1
    (
      vehicleId INT,
      recordId INT,
      patientId INT,
      calls INT,
      locationLatitute DOUBLE,
      locationLongtitue DOUBLE,
      recordTime STRING,
      direction STRING
    )
    STORED BY 'com.aliyun.odps.CsvStorageHandler' 
    WITH serdeproperties (
      'odps.properties.rolearn'='acs:ram::<uid>:role/aliyunodpsdefaultrole'
    ) 
    LOCATION 'oss://oss-cn-hangzhou-internal.aliyuncs.com/oss-mc-test/Demo1/';
    
    -- 您可以执行desc extended mc_oss_csv_external1;命令查看创建好的OSS外部表结构信息。
  2. 查询非分区外表。

    SELECT * FROM mc_oss_csv_external1;

    返回结果如下:

    +------------+------------+------------+------------+------------------+-------------------+----------------+------------+
    | vehicleid  | recordid   | patientid  | calls      | locationlatitute | locationlongtitue | recordtime     | direction  |
    +------------+------------+------------+------------+------------------+-------------------+----------------+------------+
    | 1          | 1          | 51         | 1          | 46.81006         | -92.08174         | 9/14/2014 0:00 | S          |
    | 1          | 2          | 13         | 1          | 46.81006         | -92.08174         | 9/14/2014 0:00 | NE         |
    | 1          | 3          | 48         | 1          | 46.81006         | -92.08174         | 9/14/2014 0:00 | NE         |
    | 1          | 4          | 30         | 1          | 46.81006         | -92.08174         | 9/14/2014 0:00 | W          |
    | 1          | 5          | 47         | 1          | 46.81006         | -92.08174         | 9/14/2014 0:00 | S          |
    | 1          | 6          | 9          | 1          | 46.81006         | -92.08174         | 9/15/2014 0:00 | S          |
    | 1          | 7          | 53         | 1          | 46.81006         | -92.08174         | 9/15/2014 0:00 | N          |
    | 1          | 8          | 63         | 1          | 46.81006         | -92.08174         | 9/15/2014 0:00 | SW         |
    | 1          | 9          | 4          | 1          | 46.81006         | -92.08174         | 9/15/2014 0:00 | NE         |
    | 1          | 10         | 31         | 1          | 46.81006         | -92.08174         | 9/15/2014 0:00 | N          |
    +------------+------------+------------+------------+------------------+-------------------+------------+----------------+
  3. 写入数据至非分区外表,并查看数据是否已成功写入。

    INSERT INTO mc_oss_csv_external1 VALUES(1,12,76,1,46.81006,-92.08174,'9/14/2014 0:10','SW');
    SELECT * FROM mc_oss_csv_external1 WHERE recordId=12;

    返回结果如下:

    +------------+------------+------------+------------+------------------+-------------------+----------------+------------+
    | vehicleid  | recordid   | patientid  | calls      | locationlatitute | locationlongtitue | recordtime     | direction  |
    +------------+------------+------------+------------+------------------+-------------------+----------------+------------+
    | 1          | 12         | 76         | 1          | 46.81006         | -92.08174         | 9/14/2014 0:10 | SW         |
    +------------+------------+------------+------------+------------------+-------------------+----------------+------------+

    查看OSS路径Demo1/下已产生新文件。image

通过内置文本数据解析器创建OSS外部表-分区表

  1. 示例数据中的Demo2/目录建立映射关系。创建OSS外部表并引入分区数据的命令示例如下。

    CREATE EXTERNAL TABLE IF NOT EXISTS mc_oss_csv_external2
    (
      vehicleId INT,
      recordId INT,
      patientId INT,
      calls INT,
      locationLatitute DOUBLE,
      locationLongtitue DOUBLE,
      recordTime STRING
    )
    PARTITIONED BY (
      direction STRING
    )
    STORED BY 'com.aliyun.odps.CsvStorageHandler' 
    WITH serdeproperties (
      'odps.properties.rolearn'='acs:ram::<uid>:role/aliyunodpsdefaultrole'
    ) 
    LOCATION 'oss://oss-cn-hangzhou-internal.aliyuncs.com/oss-mc-test/Demo2/';
    
    --引入分区数据。
    MSCK REPAIR TABLE mc_oss_csv_external2 ADD PARTITIONS;
    --等效于如下语句。
    ALTER TABLE mc_oss_csv_external2 ADD PARTITION (direction = 'N') PARTITION (direction = 'NE') PARTITION (direction = 'S') PARTITION (direction = 'SW') PARTITION (direction = 'W');
    
    -- 您可以执行DESC EXTENDED mc_oss_csv_external2;命令查看创建好的外部表结构信息。
  2. 查询分区外表。

    SELECT * FROM mc_oss_csv_external2 WHERE direction='NE';

    返回结果如下:

    +------------+------------+------------+------------+------------------+-------------------+----------------+------------+
    | vehicleid  | recordid   | patientid  | calls      | locationlatitute | locationlongtitue | recordtime     | direction  |
    +------------+------------+------------+------------+------------------+-------------------+----------------+------------+
    | 1          | 2          | 13         | 1          | 46.81006         | -92.08174         | 9/14/2014 0:00 | NE         |
    | 1          | 3          | 48         | 1          | 46.81006         | -92.08174         | 9/14/2014 0:00 | NE         |
    | 1          | 9          | 4          | 1          | 46.81006         | -92.08174         | 9/15/2014 0:00 | NE         |
    +------------+------------+------------+------------+------------------+-------------------+----------------+------------+
  3. 写入数据至分区外表,并查看是否已成功写入。

    INSERT INTO mc_oss_csv_external2 PARTITION(direction='NE') VALUES(1,12,76,1,46.81006,-92.08174,'9/14/2014 0:10');
    SELECT * FROM mc_oss_csv_external2 WHERE direction='NE' AND recordId=12;

    返回结果如下:

    +------------+------------+------------+------------+------------------+-------------------+----------------+------------+
    | vehicleid  | recordid   | patientid  | calls      | locationlatitute | locationlongtitue | recordtime     | direction  |
    +------------+------------+------------+------------+------------------+-------------------+----------------+------------+
    | 1          | 12         | 76         | 1          | 46.81006         | -92.08174         | 9/14/2014 0:10 | NE         |
    +------------+------------+------------+------------+------------------+-------------------+----------------+------------+

    查看OSS路径Demo2/direction=NE下已产生新文件。image

通过内置文本数据解析器创建OSS外部表-压缩数据

本示例创建以GZIP压缩的CSV格式外表,进行数据读取和写入操作。

  1. 创建内部表并写入测试数据,用来进行后续的写入测试。

    CREATE TABLE vehicle_test(
      vehicleid INT, 
      recordid INT, 
      patientid INT, 
      calls INT, 
      locationlatitute DOUBLE, 
      locationlongtitue DOUBLE, 
      recordtime STRING, 
      direction STRING
    );
    
    INSERT INTO vehicle_test VALUES (1,1,51,1,46.81006,-92.08174,'9/14/2014 0:00','S');
  2. 创建以GZIP压缩的CSV格式外表,与示例数据中的Demo3/(压缩数据)目录建立映射关系。创建OSS外部表命令示例如下。

    CREATE EXTERNAL TABLE IF NOT EXISTS mc_oss_csv_external3
    (
      vehicleId INT,
      recordId INT,
      patientId INT,
      calls INT,
      locationLatitute DOUBLE,
      locationLongtitue DOUBLE,
      recordTime STRING,
      direction STRING
    )
    PARTITIONED BY (dt STRING)
    STORED BY 'com.aliyun.odps.CsvStorageHandler' 
    WITH serdeproperties (
      'odps.properties.rolearn'='acs:ram::<uid>:role/aliyunodpsdefaultrole',
      'odps.text.option.gzip.input.enabled'='true',
      'odps.text.option.gzip.output.enabled'='true' 
    ) 
    LOCATION 'oss://oss-cn-hangzhou-internal.aliyuncs.com/oss-mc-test/Demo3/';
    
    -- 引入分区数据
    MSCK REPAIR TABLE mc_oss_csv_external3 ADD PARTITIONS;
    
    -- 您可以执行DESC EXTENDED mc_oss_csv_external3;命令查看创建好的外部表结构信息。
  3. 使用MaxCompute客户端,从OSS中读取数据。命令示例如下:

    说明

    如果OSS压缩数据为开源数据格式,需要在SQL语句前添加set odps.sql.hive.compatible=true;命令,与SQL语句一起提交执行。

    --开启全表扫描,仅此Session有效。
    SET odps.sql.allow.fullscan=true;
    SELECT recordId, patientId, direction FROM mc_oss_csv_external3 WHERE patientId > 25;

    返回结果如下:

    +------------+------------+------------+
    | recordid   | patientid  | direction  |
    +------------+------------+------------+
    | 1          | 51         | S          |
    | 3          | 48         | NE         |
    | 4          | 30         | W          |
    | 5          | 47         | S          |
    | 7          | 53         | N          |
    | 8          | 63         | SW         |
    | 10         | 31         | N          |
    +------------+------------+------------+
  4. 读取内部表的数据写入至OSS外表。

    通过MaxCompute客户端对外部表执行INSERT OVERWRITEINSERT INTO命令,将数据写入OSS。

    INSERT INTO TABLE mc_oss_csv_external3 PARTITION (dt='20250418') SELECT * FROM vehicle_test;

    执行成功后,您可在OSS目录下查看导出的文件。

创建OSS外部表并指定对应OSS文件的第一行为表头

示例数据oss-mc-testBucket下创建Demo11目录,并执行如下语句:

--创建外部表
CREATE EXTERNAL TABLE mf_oss_wtt
(
  id BIGINT,
  name STRING,
  tran_amt DOUBLE
)
STORED BY 'com.aliyun.odps.CsvStorageHandler'
WITH serdeproperties (
  'odps.text.option.header.lines.count' = '1',
  'odps.sql.text.option.flush.header' = 'true'
)
LOCATION 'oss://oss-cn-hangzhou-internal.aliyuncs.com/oss-mc-test/Demo11/';

--插入数据
INSERT OVERWRITE TABLE mf_oss_wtt VALUES (1, 'val1', 1.1),(2, 'value2', 1.3);

--查询数据
--在建表的时候可以把所有字段建成string,否则表头读取时会报错。
--或者在建表的时候需要加跳过表头的参数:'odps.text.option.header.lines.count' = '1'
SELECT * FROM mf_oss_wtt;

返回结果如下:

+----------+--------+------------+
| id       | name   | tran_amt   |
+----------+--------+------------+
| 1        | val1   | 1.1        |
| 2        | value2 | 1.3        |
+----------+--------+------------+

创建OSS外部表且外部表列数与OSS数据列数不一致

  1. 示例数据oss-mc-testBucket下创建demo目录,并上传test.csv文件。test.csv文件内容如下。

    1,kyle1,this is desc1
    2,kyle2,this is desc2,this is two
    3,kyle3,this is desc3,this is three, I have 4 columns
  2. 创建外部表。

    1. 指定对于列数不一致的行的处理方式为TRUNCATE

      --删除表
      DROP TABLE test_mismatch;
      --新建外部表
      CREATE EXTERNAL TABLE IF NOT EXISTS test_mismatch
      (
        id string,
        name string,
        dect string,
        col4 string
      )
      STORED BY 'com.aliyun.odps.CsvStorageHandler'
      WITH serdeproperties ('odps.sql.text.schema.mismatch.mode' = 'truncate')
      LOCATION 'oss://oss-cn-hangzhou-internal.aliyuncs.com/oss-mc-test/demo/';
    2. 指定对于列数不一致的行的处理方式为IGNORE

      --删除表
      DROP TABLE test_mismatch01;
      --新建外部表
      CREATE EXTERNAL TABLE IF NOT EXISTS test_mismatch01
      (
        id STRING,
        name STRING,
        dect STRING,
        col4 STRING
      )
      STORED BY 'com.aliyun.odps.CsvStorageHandler'
      WITH serdeproperties ('odps.sql.text.schema.mismatch.mode' = 'ignore')
      LOCATION 'oss://oss-cn-hangzhou-internal.aliyuncs.com/oss-mc-test/demo/';
    3. 查询表数据。

      • 查询test_mismatch表。

        SELECT * FROM test_mismatch;
        
        --返回结果
        +----+-------+---------------+---------------+
        | id | name  | dect          | col4          |
        +----+-------+---------------+---------------+
        | 1  | kyle1 | this is desc1 | NULL          |
        | 2  | kyle2 | this is desc2 | this is two   |
        | 3  | kyle3 | this is desc3 | this is three |
        +----+-------+---------------+---------------+
      • 查询test_mismatch01表。

        SELECT * FROM test_mismatch01;
        
        --返回结果
        +----+-------+----------------+-------------+
        | id | name  | dect           | col4        |
        +----+-------+----------------+-------------+
        | 2  | kyle2 | this is desc2  | this is two  
        +----+-------+----------------+-------------+

创建CSV格式的OSS外部表-自定义各种时间数据类型

CSV自定义时间类型的解析与输出格式详情,请参见Smart Parse更灵活的类型能力

  1. 创建各时间数据类型的CSV外表(datetime/timestamp/timestamp_ntz)。

    CREATE EXTERNAL TABLE test_csv
    (
      col_date DATE,
      col_datetime DATETIME,
      col_timestamp TIMESTAMP,
      col_timestamp_ntz TIMESTAMP_NTZ
    )
    STORED BY 'com.aliyun.odps.CsvStorageHandler'
    LOCATION 'oss://oss-cn-hangzhou-internal.aliyuncs.com/oss-mc-test/demo/'
    TBLPROPERTIES (
      'odps.text.option.date.io.format' = 'MM/dd/yyyy',
      'odps.text.option.datetime.io.format' = 'yyyy-MM-dd-HH-mm-ss x',
      'odps.text.option.timestamp.io.format' = 'yyyy-MM-dd HH-mm-ss VV',
      'odps.text.option.timestamp_ntz.io.format' = 'yyyy-MM-dd HH:mm:ss.SS'
    );
    
    INSERT OVERWRITE test_csv 
      VALUES(DATE'2025-02-21', DATETIME'2025-02-21 08:30:00', TIMESTAMP'2025-02-21 12:30:00', TIMESTAMP_NTZ'2025-02-21 16:30:00.123456789');
  2. 插入数据后,CSV文件的内容为:

    02/21/2025,2025-02-21-08-30-00 +08,2025-02-21 12-30-00 Asia/Shanghai,2025-02-21 16:30:00.12
  3. 再次读数据,可以看到结果。

    SELECT * FROM test_csv;

    返回结果如下:

    +------------+---------------------+---------------------+------------------------+
    | col_date   | col_datetime        | col_timestamp       | col_timestamp_ntz      |
    +------------+---------------------+---------------------+------------------------+
    | 2025-02-21 | 2025-02-21 08:30:00 | 2025-02-21 12:30:00 | 2025-02-21 16:30:00.12 |
    +------------+---------------------+---------------------+------------------------+