PostgreSQL 9.5 - 解码/select 用 utf8 解决错误的案例不起作用

PostgreSQL 9.5 - decode / select case to solve error with utf8 doesn't work

继续我的 - “将 oracle 迁移到 postgresql 用于编码“UTF8”的无效字节序列:0x00”

我正在尝试将来自远程 Oracle table 的数据插入本地 PostgreSQL table(通过 oracle_fdw 扩展)。我的 Oracle table 有一个名为 street 的列,它有有效的字符串值,有时下一个无效的(在 PostgreSQL 中)字符串:' ' (space).

当我尝试复制列值时,出现了我在上文和上次 post 中提到的错误。我知道我需要在将 oracle 数据插入 PostgreSQL 之前更改它。我必须即时进行,所以我尝试在 PostgreSQL 中搜索 oracle decode func。我找到了两个解决方案并且我都使用了它们但是我得到了同样的错误:

1.using select 大小写:

mydb=>select *,(case when v.street=' ' then null END) from customer_prod v;
ERROR:  invalid byte sequence for encoding "UTF8": 0x00
CONTEXT:  converting column "street" for foreign table scan of 
 "customer_prod", row 254148

2.using 来自 orafce 扩展的解码函数:

mydb=>select decode(street,' ',null) from customer_prod;
ERROR:  invalid byte sequence for encoding "UTF8": 0x00

所以,我仍然遇到错误。我该如何解决这个问题?

将值从 Oracle 传输到 PostgreSQL 时会发生错误,因此 post- 处理不会阻止错误。

为了演示,让我们创建一个显示问题的 Oracle table:

CREATE TABLE nulltest(
   id number(5) CONSTRAINT nulltest_pkey PRIMARY KEY,
   val varchar2(10 CHAR)
);

INSERT INTO nulltest VALUES (1, 'schön');
INSERT INTO nulltest VALUES (2, 'bö' || CHR(0) || 'se');
INSERT INTO nulltest VALUES (3, 'egal');

COMMIT;

让我们在 PostgreSQL 中为其创建一个外部 table:

CREATE FOREIGN TABLE nulltest (
   id integer OPTIONS (key 'true') NOT NULL,
   val varchar(10)
) SERVER oracle
   OPTIONS (table 'NULLTEST');

SELECT * FROM nulltest;

ERROR:  invalid byte sequence for encoding "UTF8": 0x00
CONTEXT:  converting column "val" for foreign table scan of "nulltest", row 2

现在最简单的方法是创建一个过滤掉零字符的外部 table:

CREATE FOREIGN TABLE filter_nulltest (
   id integer OPTIONS (key 'true') NOT NULL,
   val varchar(10)
) SERVER oracle
   OPTIONS (table '(SELECT id, replace(val, CHR(0), NULL) FROM nulltest)');

SELECT * FROM filter_nulltest;

┌────┬───────┐
│ id │  val  │
├────┼───────┤
│  1 │ schön │
│  2 │ böse  │
│  3 │ egal  │
└────┴───────┘
(3 rows)

另一个效率较低的选项是创建一个函数来捕获错误行并向您报告错误行,以便您可以在 Oracle 端修复它们:

CREATE OR REPLACE FUNCTION get_nulltest() RETURNS SETOF nulltest
   LANGUAGE plpgsql AS
$$DECLARE
   v_id integer;
   n nulltest;
BEGIN
   FOR v_id IN SELECT id FROM nulltest
   LOOP
      BEGIN
         SELECT nulltest.* INTO n
            FROM nulltest
            WHERE id = v_id;
         RETURN NEXT n;
      EXCEPTION
         WHEN OTHERS THEN
            RAISE NOTICE 'Caught error % for id=%: %', SQLSTATE, v_id, SQLERRM;
      END;
   END LOOP;
END;$$;

SELECT * FROM get_nulltest();

NOTICE:  Caught error 22021 for id=2: invalid byte sequence for encoding "UTF8": 0x00
┌────┬───────┐
│ id │  val  │
├────┼───────┤
│  1 │ schön │
│  3 │ egal  │
└────┴───────┘
(2 rows)