“未知”和类型推断的规则是什么?

Eva*_*oll 4 sql postgresql types type-inference type-promotion

我正在寻找以下内容的解释,如果我运行这样的东西,我会得到一个unknown类型,

SELECT pg_typeof(a)
FROM ( SELECT null ) AS t(a);
 pg_typeof 
-----------
 unknown
(1 row)
Run Code Online (Sandbox Code Playgroud)

然而,随着更多的复杂性,它变得text神奇,

SELECT pg_typeof(a)
FROM (
  SELECT null
  UNION SELECT null
) AS t(a);
 pg_typeof 
-----------
 text
(1 row)
Run Code Online (Sandbox Code Playgroud)

显式转换不会改变这一点,这也会返回text

SELECT pg_typeof(a)
FROM (
  SELECT null::unknown
  UNION SELECT null::unknown               
) AS t(a);
Run Code Online (Sandbox Code Playgroud)

有趣的是,这有效,

SELECT pg_typeof(a)
FROM (
  SELECT null
  UNION SELECT 42                  
) AS t(a);
Run Code Online (Sandbox Code Playgroud)

但这不,

SELECT pg_typeof(a)
FROM (
  SELECT null
  UNION SELECT null
  UNION SELECT 42
) AS t(a);
Run Code Online (Sandbox Code Playgroud)

unknown如果在上述情况下假定它是文本,该类型到底有什么用途?

Lau*_*lbe 5

实际上,我将尝试回答其中的三个问题。

  1. 的目的是unknown什么?

    这是最初分配给 SQL 语句中的 NULL 和字符串文字的数据类型。如果text立即为此类文字分配类型,则很难推断出正确的类型。

    例如,您想myfunc('hello')调用myfunc(character varying),但没有从textto 的隐式类型转换character varying(如果您创建了一个,它会导致歧义)。

  2. 为什么SELECT null返回类型为 的列unknown

    传统的答案是:因为用户没有指定类型。

    然而,这种行为一直存在问题。例如,如果您创建一个这样的表:

    CREATE TABLE test
       AS SELECT 'hello';
    
    Run Code Online (Sandbox Code Playgroud)

    你最终会得到一个类型为 的列unknown,这是不可取的,并且会导致进一步的问题。类型unknown真的不应该是用户可见的,而是一个实现细节。

    因此,这个提交改变了从 PostgreSQL v10 开始的行为:现在任何unknown留在 aSELECTRETURNINGlist 中的s都被强制为text,并且不能使用类型为 的列创建表unknown

  3. 为什么SELECT NULL UNION SELECT 42有效,但不行SELECT NULL UNION SELECT NULL UNION SELECT 42

    这是由于类型转换规则UNION是左关联的,所以后面的查询被解释为

    (SELECT NULL UNION SELECT NULL) UNION SELECT 42;
    
    Run Code Online (Sandbox Code Playgroud)

    现在第一个UNION解析为数据类型,text因为规则 3:

    如果所有输入都是未知类型,则解析为文本类型(字符串类别的首选类型)。

    UNION由于规则 4,这在尝试解析第二个类型时会导致错误:

    如果非未知输入并非都属于同一类型类别,则失败。

    另一方面,在查询中

    SELECT NULL UNION SELECT 42;
    
    Run Code Online (Sandbox Code Playgroud)

    “NULL”有类型unknown,“42”有类型integer(为没有小数点的数字文字选择的类型)。

    规则 5

    选择第一个非未知输入类型,它是该类别中的首选类型(如果有)。

    不适用于此处,因为integer在其类别中不是首选类型(即oiddouble precision),因此使用规则 6:

    否则,选择允许所有前面的非未知输入隐式转换为它的最后一个非未知输入类型。

    这导致integer.