UNION,CASE和相关构造

SQL UNION构造必须把那些可能不太相似的类型匹配起来成为一个结果集。解析算法分别应用于联合查询的每个输出字段。INTERSECT和EXCEPT构造对不相同的类型使用和UNION相同的算法进行解析。CASE、ARRAY、VALUES、GREATEST和LEAST构造也使用同样的算法匹配它的部件表达式并且选择一个结果数据类型。

UNION,CASE和相关构造解析

  • 如果所有输入都是相同的类型,并且不是unknown类型,那么解析成这种类型。
  • 如果所有输入都是unknown类型则解析成text类型(字符串类型范畴的首选类型)。否则,忽略unknown输入。
  • 如果输入不属于同一个类型范畴,失败。(unknown类型除外)
  • 如果输入类型是同一个类型范畴,则选择该类型范畴的首选类型。(例外:union操作会选择第一个分支的类型作为所选类型。)

    UNION,CASE和相关构造 - 图1 说明:
    系统表pg_type中typcategory表示数据类型范畴, typispreferred表示是否是typcategory分类中的首选类型。

  • 把所有输入转换为所选的类型(对于字符串保持原有长度)。如果从给定的输入到所选的类型没有隐式转换则失败。

  • 若输入中含json、txid_snapshot、sys_refcursor或几何类型,则不能进行union。

对于case和coalesce,在TD兼容模式下的处理

  • 如果所有输入都是相同的类型,并且不是unknown类型,那么解析成这种类型。
  • 如果所有输入都是unknown类型则解析成text类型。
  • 如果输入字符串(包括unknown,unknown当text来处理)和数字类型,那么解析成字符串类型,如果是其他不同的类型范畴,则报错。
  • 如果输入类型是同一个类型范畴,则选择该类型的优先级较高的类型。
  • 把所有输入转换为所选的类型。如果从给定的输入到所选的类型没有隐式转换则失败。

示例

示例1:Union中的待定类型解析。这里,unknown类型文本’b’将被解析成text类型。

  1. postgres=# SELECT text 'a' AS "text" UNION SELECT 'b';
  2. text
  3. ------
  4. a
  5. b
  6. (2 rows)

示例2:简单Union中的类型解析。文本1.2的类型为numeric,而且integer类型的1可以隐含地转换为numeric,因此使用这个类型。

  1. postgres=# SELECT 1.2 AS "numeric" UNION SELECT 1;
  2. numeric
  3. ---------
  4. 1
  5. 1.2
  6. (2 rows)

示例3:转置Union中的类型解析。这里,因为类型real不能被隐含转换成integer,但是integer可以隐含转换成real,那么联合的结果类型将是real。

  1. postgres=# SELECT 1 AS "real" UNION SELECT CAST('2.2' AS REAL);
  2. real
  3. ------
  4. 1
  5. 2.2
  6. (2 rows)

示例4:TD模式下,coalesce参数输入int和varchar类型,那么解析成varchar类型。ORA模式下会报错。

  1. --在A模式下,创建A兼容模式的数据库a_1
  2. postgres=# CREATE DATABASE a_1 dbcompatibility = 'A';
  3. --切换数据库为a_1
  4. postgres=# \c a_1
  5. --创建表t1
  6. a_1=# CREATE TABLE t1(a int, b varchar(10));
  7. --查看coalesce参数输入intvarchar类型的查询语句的执行计划。
  8. a_1=# EXPLAIN SELECT coalesce(a, b) FROM t1;
  9. ERROR: COALESCE types integer and character varying cannot be matched
  10. LINE 1: EXPLAIN SELECT coalesce(a, b) FROM t1;
  11. ^
  12. CONTEXT: referenced column: coalesce
  13. --删除表。
  14. a_1=# DROP TABLE t1;
  15. --切换数据库为postgres
  16. a_1=# \c postgres
  17. --在TD模式下,创建TD兼容模式的数据库td_1
  18. postgres=# CREATE DATABASE td_1 dbcompatibility = 'C';
  19. --切换数据库为td_1
  20. postgres=# \c td_1
  21. --创建表t2
  22. td_1=# CREATE TABLE t2(a int, b varchar(10));
  23. --查看coalesce参数输入intvarchar类型的查询语句的执行计划。
  24. td_1=# EXPLAIN VERBOSE select coalesce(a, b) from t2;
  25. QUERY PLAN
  26. ---------------------------------------------------------------------------------------
  27. Data Node Scan (cost=0.00..0.00 rows=0 width=0)
  28. Output: (COALESCE((t2.a)::character varying, t2.b))
  29. Node/s: All dbnodes
  30. Remote query: SELECT COALESCE(a::character varying, b) AS "coalesce" FROM public.t2
  31. (4 rows)
  32. --删除表。
  33. td_1=# DROP TABLE t2;
  34. --切换数据库为postgres
  35. td_1=# \c postgres
  36. --删除ATD模式的数据库。
  37. postgres=# DROP DATABASE a_1;
  38. postgres=# DROP DATABASE td_1;