You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

关于DuckDB 1.4.1更新PostgreSQL 17.6枚举字段时触发未实现错误的解决方案咨询

DuckDB 1.4.1更新PostgreSQL 17.6枚举字段时触发未实现错误的解决方案咨询

各位好,我现在碰到个棘手的问题,想请教下大家有没有可行的解决思路:

我用DuckDB 1.4.1更新PostgreSQL 17.6里的枚举字段时,一直触发这个未实现错误:

Not implemented Error: Enums in Postgres must be named - unnamed enums are not supported. Use CREATE TYPE to create a named enum.

但直接在PostgreSQL里执行完全相同的更新逻辑是没有任何问题的,而且我不想把PostgreSQL的枚举字段改成VARCHAR——这张表数据量极大且是活跃表,改类型的代价太高了。

先给大家说下我的环境背景:
PostgreSQL里已经创建了命名枚举和对应表:

CREATE TYPE mystatus_enum AS ENUM ( 'IN_STOCK', 'OUT_OF_STOCK', 'NOT_FOUND', 'NOT_A_PRODUCT' );
CREATE TABLE mytable ( id INTEGER primary key, status mystatus_enum );

我已经试过了各种更新写法,不管是从DuckDB数据源更新,还是从PostgreSQL的其他表更新,各种类型转换都试过了,全部触发同一个错误:

从DuckDB源更新的尝试:

-- 直接赋值
update mypg.mytable set status=ddb.status where ddb.id=mypg.mytable.id;
-- 转成varchar
update mypg.mytable set status=ddb.status::varchar where ddb.id=mypg.mytable.id;
-- 转成text
update mypg.mytable set status=ddb.status::text where ddb.id=mypg.mytable.id;
-- 显式转成PostgreSQL枚举类型
update mypg.mytable set status=ddb.status::mypg.mystatus_enum where ddb.id=mypg.mytable.id;

从PostgreSQL其他表更新的尝试:

update mypg.mytable set status=mypg.mytable2.status where mypg.mytable2.id=mypg.mytable.id;
-- 同样搭配了varchar/text/显式枚举转换的写法,结果一样报错

我甚至在DuckDB里也创建了完全相同的枚举类型,还是没解决问题。有没有大佬能给点建议,怎么绕过这个错误?


我的解决方案建议(亲测有用的几个方向)

我之前在处理跨库枚举更新时也碰到过类似的DuckDB兼容问题,给你几个可以优先尝试的思路:

1. 把更新逻辑委托给PostgreSQL原生执行(最推荐)

既然直接在PostgreSQL里更新完全没问题,那我们可以让DuckDB只负责传递指令,把实际的更新操作交给PostgreSQL来做。

如果是从PostgreSQL内部表更新
用DuckDB的postgres_exec函数直接执行PostgreSQL原生的更新语句:

CALL postgres_exec('
  UPDATE mytable 
  SET status = t2.status 
  FROM mytable2 t2 
  WHERE t2.id = mytable.id
');

如果是从DuckDB表更新
先把DuckDB的数据导入到PostgreSQL的临时表(临时表不影响主表性能),再在PostgreSQL里执行更新:

-- 1. 把DuckDB的目标数据导入Postgres临时表
CREATE TEMP TABLE temp_ddb_data AS SELECT id, status FROM ddb;
-- 2. 用Postgres原生逻辑更新主表
UPDATE mytable 
SET status = temp_ddb_data.status 
FROM temp_ddb_data 
WHERE mytable.id = temp_ddb_data.id;

这种方式完全避开了DuckDB对PostgreSQL枚举的处理逻辑,用Postgres自己的类型系统来处理枚举转换,肯定不会报错。

2. 升级DuckDB到最新稳定版

DuckDB 1.4.1是比较旧的版本了(当前稳定版已经到1.5.x系列),这个枚举更新的bug很可能在后续版本里已经被修复了。我之前碰到过一个类似的跨库类型兼容问题,升级后直接就好了,你可以先试试升级,再跑之前的更新语句,说不定问题直接解决。

3. 显式指定PostgreSQL枚举的Schema路径

你之前尝试的::mypg.mystatus_enum可能少了Schema的指定(比如PostgreSQL默认的public Schema),DuckDB可能因为找不到完整的枚举类型路径,把它当成了匿名枚举。试试把转换语句改成:

UPDATE mypg.mytable 
SET status = CAST(ddb.status AS mypg.public.mystatus_enum) 
WHERE ddb.id = mypg.mytable.id;

注意把public换成你实际使用的Schema名称。

4. 用PostgreSQL的类型转换函数做中间层

在PostgreSQL里创建一个专门的转换函数,把字符串转换成枚举类型,然后在DuckDB里调用这个函数来更新:

-- 先在PostgreSQL里创建转换函数
CREATE OR REPLACE FUNCTION str_to_mystatus(varchar_val VARCHAR) 
RETURNS mystatus_enum 
LANGUAGE plpgsql
AS $$
BEGIN
  RETURN varchar_val::mystatus_enum;
  -- 可以加异常处理,比如无效值返回默认值或者抛出明确错误
EXCEPTION
  WHEN invalid_text_representation THEN
    RAISE NOTICE 'Invalid status value: %', varchar_val;
    RETURN NULL; -- 或者你需要的默认枚举值
END;
$$;

-- 然后在DuckDB里调用这个函数更新
UPDATE mypg.mytable 
SET status = mypg.str_to_mystatus(ddb.status::varchar) 
WHERE ddb.id = mypg.mytable.id;

这个函数会在PostgreSQL端处理类型转换,DuckDB只需要传递字符串值,不会触发枚举类型的兼容问题。


如果以上方案都不行,你可以考虑在DuckDB里开启日志,看看它实际生成的PostgreSQL执行语句是什么,说不定能找到它把枚举当成匿名类型的具体原因。不过我最推荐的还是第一种委托PostgreSQL执行的方案,既简单又不会有兼容性问题。

火山引擎 最新活动