【问题标题】:What is the rule for `unknown` and type inference?“未知”和类型推断的规则是什么?
【发布时间】:2017-09-23 06:36:53
【问题描述】:

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

SELECT pg_typeof(a)
FROM ( SELECT null ) AS t(a);
 pg_typeof 
-----------
 unknown
(1 row)

然而,随着复杂度的增加,它神奇地变成了text

SELECT pg_typeof(a)
FROM (
  SELECT null
  UNION SELECT null
) AS t(a);
 pg_typeof 
-----------
 text
(1 row)

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

SELECT pg_typeof(a)
FROM (
  SELECT null::unknown
  UNION SELECT null::unknown               
) AS t(a);

有趣的是,这很有效,

SELECT pg_typeof(a)
FROM (
  SELECT null
  UNION SELECT 42                  
) AS t(a);

但事实并非如此,

SELECT pg_typeof(a)
FROM (
  SELECT null
  UNION SELECT null
  UNION SELECT 42
) AS t(a);

如果unknown 类型在上述情况下被假定为文本,它有什么用途?

【问题讨论】:

标签: sql postgresql types type-inference type-promotion


【解决方案1】:

我将尝试回答其中的三个问题。

  1. unknown的目的是什么?

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

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

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

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

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

    CREATE TABLE test
       AS SELECT 'hello';
    

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

    因此,this commit 改变了 PostgreSQL v10 上的行为:现在任何留在SELECTRETURNING 列表中的unknowns 都被强制为text,并且无法使用类型为列的列创建表unknown.

  3. 为什么SELECT NULL UNION SELECT 42 有效,而SELECT NULL UNION SELECT NULL UNION SELECT 42 无效?

    这归功于type conversion rulesUNION 是左关联的,所以后面的查询被解释为

    (SELECT NULL UNION SELECT NULL) UNION SELECT 42;
    

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

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

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

    如果非未知输入不都是同一类型类别,则失败。

    另一方面,在查询中

    SELECT NULL UNION SELECT 42;
    

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

    规则 5

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

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

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

    这会产生integer的类型。

【讨论】:

  • 假设字符串文字是文本确实有意义,但这似乎是一种笨拙的方法。总之很好的答案。理想情况下,延迟将类型归于未知,直到结果集完成而不是在第一个联合时才更有意义。
猜你喜欢
  • 1970-01-01
  • 2016-08-07
  • 2012-09-15
  • 2023-01-14
  • 1970-01-01
  • 2020-09-22
  • 2019-10-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多