本文为您介绍MaxCompute2.0支持的数据类型,包括基本数据类型和复杂类型。

基本数据类型

MaxCompute支持多种数据类型,特别是MaxCompute升级到2.0后支持的基本数据类型更丰富,可参考本文查看基本数据类型和复杂类型。

由于原类型系统设计原因,如果您需要使用新数据类型系统,需首先设置set odps.sql.type.system.odps2=true;setproject odps.sql.type.system.odps2=true;,否则可能产生报错xxxx type is not enabled in current mode。同时,需要注意对原有任务的影响,具体请参见本文中提到的新类型相关注意事项。
说明 新数据类型开关odps.sql.type.system.odps2设置仅支持字母小写。
类型 是否2.0版本新增 常量定义 描述
TINYINT 1Y、-127Y 8位有符号整形,取值范围:-128~127。
SMALLINT 32767S、-100S 16位有符号整形,取值范围:-32768~32767。
INT 1000、-15645787 32位有符号整形,取值范围:-2 31 ~2 31 -1。详见注释1和注释2。
BIGINT 100000000000L、-1L 64位有符号整形, 取值范围:-2 63 +1~2 63 -1。
FLOAT 32位二进制浮点型。
DOUBLE 3.1415926 1E+7 64位二进制浮点型。
DECIMAL 3.5BD、 99999999999.9999999BD 10进制精确数字类型,整形部分取值范围:-10 36 +1~10 36 -1, 小数部分精确到10 -18 。详见注释5。
VARCHAR(n) 变长字符类型,n为长度,取值范围:1~65535。详见注释3。
STRING “abc”、’bcd’、”alibaba”、‘inc’ 字符串类型,目前长度限制为8M。详见注释4。
BINARY 二进制数据类型,目前长度限制为8M。
DATETIME DATETIME ‘2017-11-11 00:00:00’ 日期时间类型,取值范围:0000年1月1日~9999年12月31日,精确到毫秒。详见注释6。
TIMESTAMP TIMESTAMP ‘2017-11-11 00:00:00.123456789’ 与时区无关的时间戳类型,取值范围:0000年1月1日~9999年12月31日23.59:59.999999999,精确到纳秒。
说明 对于部分时区相关的函数,例如cast(<a timestamp> as string),会要求与时区无关的TIMESTAMP按照当前时区相符的方式来展现。
BOOLEAN True、False BOOLEAN类型,取值范围:True、False。

上述的各种数据类型均可为Null。

说明

新类型系统相关注意事项:

  • 新类型使用范围:
    • MaxCompute SQL支持新数据类型。
    • 新版本MapReduce支持新数据类型。
    • SDK 0.27.2-public版本及以上、客户端0.27.0版本及以上支持新数据类型。
  • 打开新类型
    由于历史原因,目前新数据类型默认不能使用,要使用需执行Flag开启(Flag命令仅支持小写):
    • Session级别:SQL或者新版MR任务涉及使用新数据类型(TINYINT、SMALLINT、INT、FLOAT、VARCHAR、TIMESTAMP、BINARY)时,需在语句前加上set语句set odps.sql.type.system.odps2=true;,并与该语句一起提交执行。通过MaxCompute Studio提交的SQL工具默认自动加上该set语句提交执行。应用示例请参见创建和查看表
    • Project级别(需特别注意打开后的影响):即支持对Project级别进行新类型打开。Project的Owner可根据需要对Project进行设置,命令为:
      setproject odps.sql.type.system.odps2=true;

      setproject的详细说明请参见其他操作

  • 打开新类型odps.sql.type.system.odps2的主要影响:
    • 注释1:关键字INT语义的变化。打开新类型后SQL中的INT关键字是指32位整型,例如cast(a as INT)是将a类型转换成32位整型。未打开新类型会被转换成BIGINT,是64位。例如SQL中写cast(a as INT)相当于cast(a as BIGINT),或create table t(a INT)相当于create table a (BIGINT)。为与MaxCompute原有模式兼容,新类型系统在未设定odps.sql.type.system.odps2=true;的情况下,仍保留此转换,但会报告一个警告:提示INT被当作BIGINT处理了。如果您的脚本有此种情况,建议全部改写为BIGINT,避免混淆。
    • 整型常量的语义变化
      例如SELECT 1 + a; 中的整型常量1:
      • 未打开新类型时,会被当做BIGINT来处理(如果这个常量太长了,超过了BIGINT的值域,如1000000000000000000000000,则会被当做DOUBLE来处理)。
      • 打开新类型后, 整形常量会优先被解释为INT类型1就是32位整形的1(如果这个常量的值超过了INT的值域而又没有超过BIGINT的值域,则会解释为 BIGINT类型。如果超过了BIGINT的值域,则会解释为DOUBLE类型)。
      • 可能出现的兼容性问题:类型是INT导致后续一些操作调用到的函数原型不一致,包括落盘(即写入磁盘)后生成的新类型表会导致周边工具以及后续作业的行为改变。
    • 隐式类型转换规则变化
      • 打开新类型时某些隐式类型转换会被禁用,包括STRING->BIGINT,STRING->DATETIME,DOUBLE->BIGINT,DECIMAL->DOUBLE,DECIMAL->BIGINT都是有精度损失或者报错的风险。这种情况可以通过cast函数做强制转换的方式来解决。
      • 隐式类型转换影响较大的地方是函数调用和insert,未开启新类型时能执行通过的SQL,在开启新后执行会报错。
    • 支持的操作,内置函数,UDF不一样
      在未打开新类型时,部分以新类型作为参数和返回值的操作及内置函数会被直接忽略,打开新类型后才可以正常使用它们。主要影响如下:
      • 一些内置操作必须打开新类型Flag才能使用,例如返回INT类型的函数(接受INT作为参数的内置函数,基本都有BIGINT的重载),例如YEAR、QUARTER、MONTH、DAY、HOUR、MINUTE、SECOND、MILLISECOND、NANOSECOND、DAYOFMONTH、WEEKOFYEAR。这些函数实际上可以用DATEPART内置函数来实现。
      • UDF的Resolve不一致。例如UDF包含BIGINT和INT两个重载,原类型系统下由于无法识别INT,一定会执行BIGINT的重载,而新类型系统下可能会被解析到INT的重载。
    • BIGINT关键字的解析不一样

      在旧类型系统下,单独一个整形常量,例如123,在旧类型下是BIGINT类型,在新类型下是INT类型。可能的兼容性问题:类型是INT会导致后续一些操作调用到的函数原型不一致,包括落盘(即写入磁盘)后生成的新类型表会导致周边工具以及后续作业的行为改变。

    • 分区列的类型支持不同
      • 未打开新类型时分区列的类型实际上只有STRING一种。
      • 打开新类型后,分区列的类型完整支持STRING、VARCHAR、CHAR、TINYINT、SMALLINT、INT、BIGINT这几种类型。
      • 未打开新类型时有特殊的处理:INSERT操作中的分区字段,要当做STRING类型来处理。如输入:insert overwrite table t partition (pt = 045) select ...;,注意这里045没有引号,因此这里应该是当成整型来解析,即045实际上是45。但是未打开新类型时,前面的0还在,即045,打开新类型后将去掉这个特殊处理,即为45。
    • 集合操作的最后的LIMIT语句行为变更
      例如SELECT * FROM t1 UNION ALL SELECT * FROM t2 limit 10;语句:
      • 未打开新类型时,实际是SELECT * FROM t1 UNION ALL SELECT * FROM ( SELECT * FROM t2 limit 10) t2;
      • 打开新类型后,是SELECT * FROM (SELECT * FROM t1 UNION ALL SELECT * FROM t2 ) t limit 10;

      具有相同行为的操作,除了交集、并集和补集、INTERSECT和EXCEPT等集合操作,还有LIMIT、ORDER BY、DISTRIBUTE BY、SORT BY、CLUSTER BY操作。

    • IN表达式的类型解析不同

      IN表达式,例如 a in (1, 2, 3)

      • 未打开新类型时,要求IN后面的括号里的所有值,其类型必须一致。
      • 打开新类型后,IN后面的括号里的所有值支持隐式类型转换一致。
  • 注释2:对于INT常量,如果超过INT取值范围,会转为BIGINT。如果超过BIGINT取值范围,会转为DOUBLE。在旧版MaxCompute中,因为历史原因,SQL脚本中的所有INT类型都被转换为BIGINT,如下所示。
    create table a_bigint_table(a int); --这里的INT实际当作BIGINT处理。
    select cast(id as int) from mytable; --这里的INT实际当作BIGINT处理。
  • 注释3:VARCHAR类型常量可通过STRING常量的隐式转换表示。
  • 注释4:STRING常量支持连接,例如abcxyz会解析为abcxyz,不同部分可以写在不同行上。
  • 注释5:insert一个常量到DECIMAL字段时,请注意常量的写法需与常量定义中的格式保持一致,例如下面示例代码中的3.5BD。
    insert into test_tb(a) values (3.5BD)
  • 注释6:目前查询显示的时间值不包含毫秒。Tunnel命令通过-dfp来指定时间格式,可以指定到毫秒显示,例如tunnel upload -dfp 'yyyy-MM-dd HH:mm:ss.SSS'。关于Tunnel命令的更多信息,请参见上传下载命令

复杂数据类型

MaxCompute2.0支持的复杂类型如下表所示。

类型 定义方法 构造方法
ARRAY
  • array<int>
  • array<struct<a:int, b:string>>
  • array(1, 2, 3)
  • array(array(1, 2), array(3, 4))
MAP
  • map<string, string>
  • map<smallint, array<string>>
  • map(“k1”, “v1”, “k2”, “v2”)
  • map(1S, array(‘a’, ‘b’), 2S, array(‘x’, ‘y’))
STRUCT
  • struct<x:int, y:int>
  • struct<field1:bigint, field2:array<int>, field3:map<int, int>>
  • named_struct(‘x’, 1, ‘y’, 2)
  • named_struct(‘field1’, 100L, ‘field2’, array(1, 2), ‘field3’, map(1, 100, 2, 200))
说明 MaxCompute的复杂数据类型可以被任意嵌套使用,相关配套的内建函数说明请参见ARRAYMAPSTRUCT

PyODPS数据类型设置

如果您使用PyODPS,可以通过下列方法打开新数据类型开关:
  • 如果通过execute_sql方式调用,可以执行 o.execute_sql('set odps.sql.type.system.odps2=true;query_sql', hints={"odps.sql.submit.mode" : "script"})
  • 如果通过Dataframe调用,例如persist、execute、to_pandas等立即执行方法, 可通过hints参数设置。下图中设置方法仅针对单个作业生效。
  • 如果通过Dataframe调用,且需要全局生效,需要使用Option参数 options.sql.use_odps2_extension = True