===========================  UNION、CASE和相关结构 =========================== .. container:: sect1 :name: TYPECONV-UNION-CASE .. container:: titlepage .. container:: .. container:: .. rubric:: ``UNION``\ 、\ ``CASE``\ 和相关结构 :name: unioncase和相关结构 :class: title SQL ``UNION``\ 结构必须使可能不相似的类型匹配成为一个单一的结果集。该决定算法被独立地应用到一个联合查询的每个输出列。\ ``INTERSECT``\ 和\ ``EXCEPT``\ 采用和\ ``UNION``\ 相同的方法来决定不相似的类型。\ ``CASE``\ 、\ ``ARRAY``\ 、\ ``VALUES``\ 、\ ``GREATEST``\ 和\ ``LEAST``\ 结构使用相同的算法来使它们的组成表达式匹配并选择一种结果数据类型。 .. container:: procedure :name: id-1.5.9.10.9 **UNION\ 、\ CASE\ 和相关结构的类型决定** 1. 如果所有的输入为相同类型,并且不是\ ``unknown``\ ,那么就决定是该类型。 2. 如果任何输入是一种域类型,在所有后续步骤中都把它当做 该域的基类型。 `[12] <#ftn.id-1.5.9.10.9.3.1.1>`__ 3. 如果所有的输入为\ ``unknown``\ 类型,则决定为\ ``text``\ (字符串分类的首选类型)类型。否则,为了剩余规则,\ ``unknown``\ 输入会被忽略。 4. 如果非未知输入不全是相同的类型分类,则失败。 5. 如果有的话,选择第一个在其分类中作为首选类型的非未知输入类型。 6. 否则,选择最后的非未知输入类型,它允许所有在前面的非未知输入被隐式地转换为它(总有这样的一种类型,因为至少在列表中的第一个类型必须满足这个条件)。 7. 转换所有的输入为选定的类型。如果没有一个从给定输入到选定类型的转换将会失败。 下面是一些例子。 .. container:: example :name: id-1.5.9.10.11 **例 联合中未指定类型的类型决定** .. container:: example-contents .. code:: screen SELECT text 'a' AS "text" UNION SELECT 'b'; text ------ a b (2 rows) 这里,未知类型文字\ ``'b'``\ 将被决定为类型\ ``text``\ 。 .. container:: example :name: id-1.5.9.10.12 **例 简单联合中的类型决定** .. container:: example-contents .. code:: screen SELECT 1.2 AS "numeric" UNION SELECT 1; numeric --------- 1 1.2 (2 rows) 文字\ ``1.2``\ 是\ ``numeric``\ 类型,且\ ``integer``\ 值\ ``1``\ 可以被隐式地造型为\ ``numeric``\ ,因此使用\ ``numeric``\ 类型。 .. container:: example :name: id-1.5.9.10.13 **例 可换位联合中的类型决定** .. container:: example-contents .. code:: screen SELECT 1 AS "real" UNION SELECT CAST('2.2' AS REAL); real ------ 1 2.2 (2 rows) 这里,由于类型\ ``real``\ 被能被隐式地造型为\ ``integer``\ ,而\ ``integer``\ 可以被隐式地造型为\ ``real``\ ,联合结果类型被决定为\ ``real``\ 。 .. container:: example :name: id-1.5.9.10.14 **例 嵌套合并中的类型决定** .. container:: example-contents .. code:: screen SELECT NULL UNION SELECT NULL UNION SELECT 1; ERROR: UNION types text and integer cannot be matched 这个失败发生的原因是PostgreSQL把多个\ ``UNION``\ 当作是成对操作的嵌套,也就是说上面的输入等同于: .. code:: screen (SELECT NULL UNION SELECT NULL) UNION SELECT 1; 根据上面给定的规则,内层的\ ``UNION``\ 被确定为类型\ ``text``\ 。然后外层的\ ``UNION``\ 的输入是类型\ ``text``\ 和\ ``integer``\ ,这就导致了上面看到的错误。通过确保最左边的\ ``UNION``\ 至少有一个输入类型为想要的结果类型,就可以修正这个问题。 ``INTERSECT``\ 和\ ``EXCEPT``\ 操作也被当作成对操作。不过,这一节中描述的其他结构会在一个决定步骤中考虑所有的输入。 .. container:: footnotes -------------- .. container:: footnote :name: ftn.id-1.5.9.10.9.3.1.1 `[12] <#id-1.5.9.10.9.3.1.1>`__ 多少有些类似于对待用于操作符和函数的域输入的方式,这种行为允许 一种域类型能通过一个\ ``UNION``\ 或相似的结构保留下来, 只要用户小心地确保所有的输入都是(显式地或隐式地)准确类型。否 则会优先选择该域的基类型。