迁移 Oracle 到 PostgreSQL: 空字符串和 NULL

五月 15, 2023

Oracle 对 '' 有一些特殊的处理,默认会转成 NULL。使得 '' 可以适合任意的数据类型。

然而对于 PostgreSQL 来说,没有做这层转换,所以 '' 并不能输入给任意类型。

Oracle 示例

SQL> CREATE TABLE a(id int, c1 varchar2(10) default '', c2 date default '');
Table created.

SQL> INSERT INTO a (id) VALUES(1);
1 row created.

SQL> SELECT * FROM a WHERE c1 IS NULL;
        ID C1         C2
---------- ---------- ---------
         1

SQL> SELECT * FROM a WHERE c2 IS NULL;
        ID C1         C2
---------- ---------- ---------
         1

然而实际上这样查询却查不到结果,是不是很让人惊讶:

SQL> SELECT * FROM a WHERE c1 = '';
no rows selected

default '' 就是说默认值为 NULL。

Oracle 内部把 '' 转换成了 NULL。(不仅时间类型,字符串 Oracle 也会这么干,所以语义上很混乱,实际上个人认为是 Oracle 的一个不严谨的地方)

PostgreSQL 示例

PostgreSQL 不做这个转换,所以非字符串类型,使用 '' 都会报错。

postgres=# SELECT ''::timestamp;
ERROR:  invalid input syntax for type timestamp: ""
LINE 1: SELECT ''::timestamp;
               ^

为了兼容 Oracle,建议用户改 '' 为直接输入 NULL,语义上也通畅。

postgres=# CREATE TABLE a(id int, c1 varchar(10) default NULL, c2 timestamp(0) default NULL);
CREATE TABLE

postgres=# INSERT INTO a (id) VALUES (1);
INSERT 0 1

postgres=# SELECT * FROM a WHERE c1 IS NULL;
 id | c1 | c2
----+----+----
  1 |    |
(1 row)

postgres=# SELECT * FROM a WHERE c2 IS NULL;
 id | c1 | c2
----+----+----
  1 |    |
(1 row)

postgres=# SELECT * FROM a WHERE c1 = '';
 id | c1 | c2
----+----+----
(0 rows)