转载自:https://yq.aliyun.com/articles/228271

背景

PostgreSQL是一个强类型数据库,因此你输入的变量、常量是什么类型,是强绑定的,例如

在调用操作符时,需要通过操作符边上的数据类型,选择对应的操作符。

在调用函数时,需要根据输入的类型,选择对应的函数。

如果类型不匹配,就会报操作符不存在,或者函数不存在的错误。


  1. postgres=#select'1'+'1';
  2. ERROR:operatorisnot unique: unknown + unknown
  3. LINE 1:select'1'+'1';
  4. ^
  5. HINT:Couldnot choose a best candidate operator.You might need to add explicit type casts.

那么使用起来是不是很不方便呢?

PostgreSQL开放了类型转换的接口,同时也内置了很多的自动类型转换。来简化操作。

查看目前已有的类型转换:


  1. postgres=# \dC+
  2. List of casts
  3. Source type |Target type |Function|Implicit?|Description
  4. -----------------------------+-----------------------------+--------------------+---------------+-------------
  5. "char"| character | bpchar |in assignment |
  6. "char"| character varying | text |in assignment |
  7. "char"| integer | int4 |no|
  8. "char"| text | text | yes |
  9. abstime | date | date |in assignment |
  10. abstime | integer |(binary coercible)|no|
  11. abstime | time without time zone | time |in assignment |
  12. ................................
  13. timestamp without time zone | timestamp with time zone | timestamptz | yes |
  14. timestamp without time zone | timestamp without time zone | timestamp | yes |
  15. xml | character |(binary coercible)|in assignment |
  16. xml | character varying |(binary coercible)|in assignment |
  17. xml | text |(binary coercible)|in assignment |
  18. (246 rows)

如果你发现有些类型转换没有内置,怎么办呢?我们可以自定义转换。

当然你也可以使用这种语法,对类型进行强制转换:


  1. CAST(x AS typename)
  2. or
  3. x::typename

如何自定义类型转换(CAST)

自定义CAST的语法如下:


  1. CREATE CAST (source_type AS target_type)
  2. WITH FUNCTION function_name [(argument_type [,...])]
  3. [ AS ASSIGNMENT | AS IMPLICIT ]
  4. CREATE CAST (source_type AS target_type)
  5. WITHOUT FUNCTION
  6. [ AS ASSIGNMENT | AS IMPLICIT ]
  7. CREATE CAST (source_type AS target_type)
  8. WITH INOUT
  9. [ AS ASSIGNMENT | AS IMPLICIT ]

解释:

1、WITH FUNCTION,表示转换需要用到什么函数。

2、WITHOUT FUNCTION,表示被转换的两个类型,在数据库的存储中一致,即物理存储一致。例如text和varchar的物理存储一致。不需要转换函数。


  1. Two types can be binary coercible,
  2. which means that the conversion can be performed “for free” without invoking any function.
  3. This requires that corresponding values use the same internal representation.
  4. For instance, the types text and varchar are binary coercible both ways.
  5. Binary coercibility isnot necessarily a symmetric relationship.
  6. For example, the cast from xml to text can be performed for free in the present implementation,
  7. but the reverse direction requires a function that performs at least a syntax check.
  8. (Two types that are binary coercible both ways are also referred to as binary compatible.)

3、WITH INOUT,表示使用内置的IO函数进行转换。每一种类型,都有INPUT 和OUTPUT函数。使用这种方法,好处是不需要重新写转换函数。

除非有特殊需求,我们建议直接使用IO函数来进行转换。


  1. List of functions
  2. Schema|Name|Result data type |Argument data types |Type
  3. ------------+-----------------+------------------+---------------------+--------
  4. pg_catalog | textin | text | cstring | normal
  5. pg_catalog | textout | cstring | text | normal
  6. pg_catalog | date_in | date | cstring | normal
  7. pg_catalog | date_out | cstring | date | normal

  1. You can define a cast as an I/O conversion cast byusing the WITH INOUT syntax.
  2. An I/O conversion cast is performed by invoking the output function of the source data type,
  3. and passing the resulting string to the input function of the target data type.
  4. In many common cases,this feature avoids the need to write a separate cast functionfor conversion.
  5. An I/O conversion cast acts the same as a regular function-based cast; only the implementation is different.

4、AS ASSIGNMENT,表示在赋值时,自动对类型进行转换。例如字段类型为TEXT,输入的类型为INT,那么可以创建一个 cast(int as text) as ASSIGNMENT。


  1. If the cast is marked AS ASSIGNMENT then it can be invoked implicitly when assigning a value to a column of the target data type.
  2. For example, supposing that foo.f1 is a column of type text,then:
  3. INSERT INTO foo (f1) VALUES (42);
  4. will be allowed if the cast from type integer to type text is marked AS ASSIGNMENT,
  5. otherwise not.
  6. (We generally use the term assignment cast to describe this kind of cast.)

5、AS IMPLICIT,表示在表达式中,或者在赋值操作中,都对类型进行自动转换。(包含了AS ASSIGNMENT,它只对赋值进行转换)


  1. If the cast is marked AS IMPLICIT then it can be invoked implicitly in any context,
  2. whether assignment or internally in an expression.
  3. (We generally use the term implicit cast to describe this kind of cast.)
  4. For example, consider this query:
  5. SELECT 2+4.0;
  6. The parser initially marks the constants as being of type integer and numeric respectively.
  7. Thereisno integer + numeric operatorin the system catalogs, but there is a numeric + numeric operator.
  8. The query will therefore succeed if a cast from integer to numeric is available andis marked AS IMPLICIT —
  9. which in fact it is.
  10. The parser will apply the implicit cast and resolve the query asif it had been written
  11. SELECT CAST (2 AS numeric )+4.0;

6、注意,AS IMPLICIT需要谨慎使用,为什么呢?因为操作符会涉及到多个算子,如果有多个转换,目前数据库并不知道应该选择哪个?


  1. Now, the catalogs also provide a cast from numeric to integer.
  2. If that cast were marked AS IMPLICIT —(which it isnot—)
  3. then the parser would be faced with choosing between the above interpretation and
  4. the alternative of casting the numeric constant to integer and applying the integer + integer operator.
  5. Lacking any knowledge of which choice to prefer, it would give up and declare the query ambiguous.
  6. The fact that only one of the two casts isimplicitis the way in which we teach the parser to prefer resolution of
  7. a mixed numeric-and-integer expression as numeric;
  8. there isno built-in knowledge about that.

因此,建议谨慎使用AS IMPLICIT。建议使用AS IMPLICIT的CAST应该是非失真转换转换,例如从INT转换为TEXT,或者int转换为numeric。

而失真转换,不建议使用as implicit,例如numeric转换为int。


  1. Itis wise to be conservative about marking casts asimplicit.
  2. An overabundance of implicit casting paths can cause PostgreSQL to choose surprising interpretations of commands,
  3. or to be unable to resolve commands at all because there are multiple possible interpretations.
  4. A good rule of thumb is to make a cast implicitly invokable only for information-preserving
  5. transformations between types in the same general type category.
  6. For example, the cast from int2 to int4 can reasonably be implicit,
  7. but the cast from float8 to int4 should probably be assignment-only.
  8. Cross-type-category casts, such as text to int4, are best made explicit-only.

注意事项 + 例子

不能嵌套转换。例子

1、将text转换为date

错误方法


  1. create or replace function text_to_date(text) returns date as $$
  2. select cast($1 as date);
  3. $$ language sql strict;
  4. create cast (text as date)withfunction text_to_date(text)asimplicit;

嵌套转换后出现死循环


  1. postgres=#select text '2017-01-01'+1;
  2. ERROR: stack depth limit exceeded
  3. HINT:Increase the configuration parameter "max_stack_depth"(currently 2048kB), after ensuring the platform's stack depth limit is adequate.
  4. CONTEXT: SQL function "text_to_date" during startup
  5. SQL function "text_to_date" statement 1
  6. SQL function "text_to_date" statement 1
  7. SQL function "text_to_date" statement 1
  8. ......

正确方法


  1. create or replace function text_to_date(text) returns date as $$
  2. select to_date($1,'yyyy-mm-dd');
  3. $$ language sql strict;
  4. create cast (text as date)withfunction text_to_date(text)asimplicit;

  1. postgres=#select text '2017-01-01'+1;
  2. ?column?
  3. ------------
  4. 2017-01-02
  5. (1 row)

我们还可以直接使用IO函数来转换:


  1. postgres=# create cast (text as date)with inout asimplicit;
  2. CREATE CAST
  3. postgres=#select text '2017-01-01'+1;
  4. ?column?
  5. ------------
  6. 2017-01-02
  7. (1 row)

参考

https://www.postgresql.org/docs/10/static/sql-createcast.html

本文为云栖社区原创内容,未经允许不得转载,如需转载请发送邮件至yqeditor@list.alibaba-inc.com;如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件至:yqgroup@service.aliyun.com 进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容。

PostgreSQL 自定义自动类型转换(CAST)的更多相关文章

  1. C++程序设计方法3:自动类型转换

    方法1:在源类中定义目标类型转换运算符 #include <iostream> using namespace std; class Dst { public: Dst() { cout ...

  2. 第17课-数据库开发及ado.net 聚合函数,模糊查询like,通配符.空值处理.order by排序.分组group by-having.类型转换-cast,Convert.union all; Select 列 into 新表;字符串函数;日期函数

    第17课-数据库开发及ado.net 聚合函数,模糊查询like,通配符.空值处理.order by排序.分组group by-having.类型转换-cast,Convert.union all;  ...

  3. QVariant类及QVariant与自定义数据类型转换的方法

    这个类型相当于是Java里面的Object,它把绝大多数Qt提供的数据类型都封装起来,起到一个数据类型“擦除”的作用.比如我们的 table单元格可以是string,也可以是int,也可以是一个颜色值 ...

  4. Java自动类型转换

    ■ 自动类型转换:容量小的数据类型可以自动转换为容量大的数据类型. ■ 特例:可以讲整型常量直接赋给byte,short,char等类型变量,而不需要强制类型转换,只要不超出其表数范围. ■ 强制类型 ...

  5. BeanUtils中的自动类型转换(二)

    javabean package entity; import java.util.Date; /** * 一个测试用: * student,javaBean * @author mzy * 一个标准 ...

  6. JavaScript系列文章:自动类型转换-续

    在上一篇文章中,我们详细讲解了JavaScript中的自动类型转换,由于篇幅限制,没能覆盖到所有的转换规则,这次准备详细讲解一下. 上次我们提到了对象类型参与运算时转换规则: 1). 在逻辑环境中执行 ...

  7. JavaScript系列文章:自动类型转换

    我们都知道,JavaScript是类型松散型语言,在声明一个变量时,我们是无法明确声明其类型的,变量的类型是根据其实际值来决定的,而且在运行期间,我们可以随时改变这个变量的值和类型,另外,变量在运行期 ...

  8. struts基于ognl的自动类型转换需要注意的地方

    好吧,坎坷的过程我就不说了,直接上结论: 在struts2中使用基于ognl的自动类型转换时,Action中的对象属性必须同时添加get/set方法. 例如: 客户端表单: <s:form ac ...

  9. postgresql 关闭自动提交

    1. 简介说明             我们知道oracle中sqlplus里面执行dml语句:是需要提交commit:若错了:也可以回滚rollback: 然而在postgresql里面默认是自动提 ...

随机推荐

  1. vue 安装插件Refusing to install package with name '???'

    今天想练习使用下vux框架,安装时报错 查了下,创建项目时描述都是一样的,去package.json把name改成其它就得了

  2. arrow function、function.apply

    An arrow function expression has a shorter syntax than a function expression and does not have its o ...

  3. BootCamp 在MacBook 上安装Win10

    首先到网上下载win10的ISO光盘, 制作win10安装盘时,一直停在copy文件.最后文件还是没有copy完整. 需要手工把iso里的文件拷贝到U盘里. 否则提示source\install.wi ...

  4. day38-多进程多线程-进程池

    强大的Manage上一篇的数据共享的方式只有两种结构Value和Array.Python中提供了强大的Manage专门用来做数据共享的,其支持的类型非常多,包括,Value, Array,list,d ...

  5. Vue解决同一页面跳转页面不更新

    问题分析:路由之间的切换,其实就是组件之间的切换,不是真正的页面切换.这也会导致一个问题,就是引用相同组件的时候,会导致该组件无法更新. 方案一:使用 watch 进行监听 watch: { /* = ...

  6. Jsの练习-数组常用方法 -slice()

    slice() 返回从原数组指定开始下标到结束下标之间的项组成的新数组. slice()方法可以接收一个或两个参数,即要返回项的起始和结束位置. 在只有一个参数的情况下,slice()方法返回从该参数 ...

  7. java 集合之Map

    Map的功能方法 方法put(Object key,Object value)添加一个"值"(想要得东西)和与"值"相关的"键"(key)( ...

  8. oracle 链接

    <properties> <!--配置Hibernate方言 --> <property name="hibernate.dialect" value ...

  9. 获取map集合中key、value

    获取Map集合类中key.value的两种方法 方法一:利用Set集合中的keySet()方法 Map<String,String> map = new HashMap<String ...

  10. leetcode 421.Maximum XOR of Two Numbers in an Array

    题目中给定若干个数,然后任意选定两个数使得其异或值最大. 先利用样例中的: 3 10 5 25 2 8 这些数转换为二进制来看的话那么是先找到最高位的1然后与数组中其他的数相与后的数值保存到set中去 ...