SQL 数据类型规则

适用于:Databricks SQL check marked yes Databricks Runtime

Azure Databricks 使用几个规则来解决数据类型之间的冲突:

还可以在多种类型之间显式强制转换:

  • cast 函数在大多数类型之间进行强制转换,如果无法转换,则返回错误。
  • try_cast 函数的工作方式类似于 cast 函数,但在传递无效值时返回 NULL。
  • 其他内置函数使用提供的格式指令在不同类型之间强制转换。

类型提升

类型提升是将类型转换为同一类型系列的另一个类型的过程,其中包含原始类型的所有可能值。 因此,类型提升是一项安全操作。 例如,TINYINT 的范围为 -128127。 其所有可能值都可以安全地提升为 INTEGER

类型优先级列表

类型优先级列表定义给定数据类型的值是否可以隐式提升为另一种数据类型。

数据类型 优先级列表(从低到高)
TINYINT TINYINT -> SMALLINT -> INT -> BIGINT -> DECIMAL -> FLOAT (1) -> DOUBLE
SMALLINT SMALLINT -> INT -> BIGINT -> DECIMAL -> FLOAT > -> DOUBLE
INT INT -> BIGINT -> DECIMAL -> FLOAT > -> DOUBLE
BIGINT BIGINT -> DECIMAL -> FLOAT > -> DOUBLE
DECIMAL DECIMAL -> FLOAT > -> DOUBLE
FLOAT FLOAT (1) -> DOUBLE
DOUBLE DOUBLE
DATE DATE -> TIMESTAMP
TIMESTAMP TIMESTAMP
ARRAY ARRAY (2)
BINARY BINARY
BOOLEAN BOOLEAN
INTERVAL INTERVAL
MAP MAP (2)
STRING STRING
STRUCT STRUCT (2)

(1) 对于最不常见类型解析,会跳过 FLOAT 以避免精度损失。

(2) 对于复杂类型,优先级规则以递归顺序应用于其组件元素。

字符串和 NULL

特殊规则适用于 STRING 和未键入 NULL

  • NULL NULL 可以提升为任何其他类型。
  • STRING 可以提升为 BIGINTBINARYBOOLEANDATEDOUBLEINTERVALTIMESTAMP。 如果无法将实际字符串值强制转换为最不常见类型,Azure Databricks 会引发运行时错误。 提升为 INTERVAL 时,字符串值必须与间隔单位匹配。

类型优先级图

这是优先级层次结构的图形描述,结合了类型优先级列表字符串和 NULL 规则。

Graphical representation of precedence rules

最不常见的类型解析

一组类型中最不常见的类型是在由该类型组的所有元素构成的类型优先级图中可达到的最窄类型。

最不常见的类型解析用于:

  • 确定是否可以使用较窄类型的实参调用需要给定类型的形参的函数。
  • 为需要多个形参的共享实参类型的函数(例如 coalesceinleastgreatest)派生实参类型。
  • 派生运算符(如算术运算符或比较运算符)的操作数类型。
  • 派生表达式(如 case 表达式)的结果类型。
  • 派生数组映射构造函数的元素、键或值类型。
  • 派生 UNION、INTERSECT 或 EXCEPT 集运算符的结果类型。

如果最不常见的类型解析为 FLOAT,则应用特殊规则。 如果任何参与类型为精确的数值类型(TINYINTSMALLINTINTEGERBIGINTDECIMAL),则推出的最不常见类型均为 DOUBLE,以避免可能的数字丢失。

隐式向下转换和交叉转换

Azure Databricks 仅在函数和运算符调用上使用这些形式的隐式强制转换,并且仅可明确确定意图。

  • 隐式向下转换

    隐式向下转换会自动将较宽类型强制转换到较窄类型,而无需显式指定强制转换。 向下转换很方便,但如果实际值在窄类型中无法表示,则存在意外运行时错误的风险。

    向下转换按逆序应用类型优先级列表

  • 隐式交叉转换

    隐式交叉转换将值从一个类型系列强制转换到另一个类型系列,而无需显式指定强制转换。

    Azure Databricks 支持从以下位置进行隐式交叉转换:

    • STRING 的任何简单类型(BINARY 除外)。
    • STRING 到任何简单类型。

函数调用上的强制转换

给定解析的函数或运算符后,以下规则按其列出顺序应用于每个参数和参数对:

  • 如果受支持的参数类型是参数类型优先级关系图的一部分,Azure Databricks 会将参数提升为该参数类型。

    在大多数情况下,函数说明显式声明支持的类型或链,例如“任何数值类型”。

    例如,sin(expr)DOUBLE 上运算,但将接受任何数值。

  • 如果所需的参数类型为 STRING,并且参数类型为简单类型,则 Azure Databricks 会将参数交叉转换为字符串参数类型。

    例如,substr(str, start, len) 需要 strSTRING。 相反,可以传递数字或日期/时间类型。

  • 如果参数类型为 STRING,并且所需的参数类型为简单类型,则 Azure Databricks 会将字符串参数交叉转换为最宽受支持参数类型。

    例如,date_add(date, days) 需要 DATEINTEGER

    如果调用 date_add() 时使用了两个 STRING,则 Azure Databricks 会将第一个 STRING交叉转换DATE,将第二个 STRING 交叉转换为 INTEGER

  • 如果函数需要数值类型(例如 INTEGER)或 DATE 类型,但参数是更通用的类型(如 DOUBLETIMESTAMP),Azure Databricks 会将参数隐式向下转换为该参数类型。

    例如,date_add(date, days) 需要 DATEINTEGER

    如果调用 date_add() 时使用了 TIMESTAMPBIGINT,则 Azure Databricks 会通过删除时间组件将 TIMESTAMP向下转换DATE,将 BIGINT 向下转换为 INTEGER

  • 否则,Azure Databricks 会引发错误。

示例

coalesce 函数接受任何一组实参类型,但前提是它们共有一个最不常见类型

结果类型是实参中的最不常见类型。

-- The least common type of TINYINT and BIGINT is BIGINT
> SELECT typeof(coalesce(1Y, 1L, NULL));
  BIGINT

-- INTEGER and DATE do not share a precedence chain or support crosscasting in either direction.
> SELECT typeof(coalesce(1, DATE'2020-01-01'));
Error: Incompatible types [INT, DATE]

-- Both are ARRAYs and the elements have a least common type
> SELECT typeof(coalesce(ARRAY(1Y), ARRAY(1L)))
  ARRAY<BIGINT>

-- The least common type of INT and FLOAT is DOUBLE
> SELECT typeof(coalesce(1, 1F))
  DOUBLE

> SELECT typeof(coalesce(1L, 1F))
  DOUBLE

> SELECT typeof(coalesce(1BD, 1F))
  DOUBLE

-- The least common type between an INT and STRING is BIGINT
> SELECT typeof(coalesce(5, '6'));
  BIGINT

-- The least common type is a BIGINT, but the value is not BIGINT.
> SELECT coalesce('6.1', 5);
  Error: 6.1 is not a BIGINT

-- The least common type between a DECIMAL and a STRING is a DOUBLE
>  SELECT typeof(coalesce(1BD, '6'));
  DOUBLE

substring 函数需要 STRING 类型的字符串参数和 INTEGER 作为开头和长度参数。

-- Promotion of TINYINT to INTEGER
> SELECT substring('hello', 1Y, 2);
 he

-- No casting
> SELECT substring('hello', 1, 2);
 he

-- Casting of a literal string
> SELECT substring('hello', '1', 2);
 he

-- Downcasting of a BIGINT to an INT
> SELECT substring('hello', 1L, 2);
 he

-- Crosscasting from STRING to INTEGER
> SELECT substring('hello', str, 2)
  FROM VALUES(CAST('1' AS STRING)) AS T(str);
 he

-- Crosscasting from INTEGER to STRING
> SELECT substring(12345, 2, 2);
 23

|| (CONCAT) 允许隐式交叉转换到字符串。

-- A numeric is cast to STRING
> SELECT 'This is a numeric: ' || 5.4E10;
 This is a numeric: 5.4E10

-- A date is cast to STRING
> SELECT 'This is a date: ' || DATE'2021-11-30';
 This is a date: 2021-11-30

由于隐式向下转换,date_add 可以使用 TIMESTAMPBIGINT 调用。

> SELECT date_add(TIMESTAMP'2011-11-30 08:30:00', 5L);
 2011-12-05

由于隐式向下转换,date_add 可以使用 STRING 调用。

> SELECT date_add('2011-11-30 08:30:00', '5');
  2011-12-05