database - 为什么递归联合不适用于 PostgreSQL 中的复合类型

标签 database postgresql union composite-types

我有一个包含复合类型字段的表。当我尝试对这些字段执行递归并集时,出现错误。

drop type example_t cascade;
create type example_t as (
    value text,
    key text
);

drop table if exists example cascade;
create table example (
    inbound example_t,
    outbound example_t,

    primary key (inbound, outbound)
);

create or replace function example_fn(_attrs example_t[])
returns table (attr example_t) as $$
    with recursive target as (
        select outbound
            from example
            where array[inbound] <@ _attrs
        union
        select r.outbound
            from target as t
            inner join example as r on r.inbound = t.outbound
    )
    select unnest(_attrs)
    union
    select * from target;
$$ language sql immutable;


select example_fn(array[('foo', 'bar') ::example_t]);
ERROR: could not implement recursive UNION DETAIL: All column datatypes must be hashable. CONTEXT: SQL function "example_fn" during startup SQL state: 0A000

非递归联合有效

create or replace function example_fn(_attrs example_t[])
returns table (attr example_t) as $$
    select unnest(_attrs)
    union
    select * from example;
$$ language sql immutable;

select example_fn(array[('foo', 'bar') ::example_t]);

我可以通过这种方式重构我的函数以使其正常工作。但看起来很奇怪。我的意思是它的可读性较差。有什么办法可以做得更好吗?

create or replace function example_fn(_attrs example_t[])
returns table (attr example_t) as $$
    with recursive target as (
        select (outbound).value, (outbound).key
            from example
            where array[inbound] <@ _attrs
        union
        select (r.outbound).value, (r.outbound).key
            from target as t
            inner join example as r on r.inbound = (t.value, t.key) ::example_t
    )
    select (unnest(_attrs)).*
    union
    select * from target;
$$ language sql immutable;

最佳答案

a thread on PostgreSQL hackers mailing list以及 Tom Lane 的简短解释:

In general we consider that a datatype's notion of equality can be defined either by its default btree opclass (which supports sort-based query algorithms) or by its default hash opclass (which supports hash-based query algorithms).

The plain UNION code supports either sorting or hashing, but we've not gotten around to supporting a sort-based approach to recursive UNION. I'm not convinced that it's worth doing ...

作为解决方法,使用union all:

with recursive target as (
    select outbound
    from example
    where inbound = ('a', 'a')::example_t
    union all
    select r.outbound
    from target as t
    inner join example as r on r.inbound = t.outbound
)
select *
-- or, if necessary
-- select distinct *
from target

关于database - 为什么递归联合不适用于 PostgreSQL 中的复合类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50897005/

相关文章:

android - 将 SQLite 数据放入 ListActivity

mysql - 从 SQL 转储还原数据库时启用二进制模式

java - 带有 Android 应用程序的 Golang 后端

python - 加入所有 PostgreSQL 表并制作一个 Python 字典

sql-server - 合并两个表并覆盖先前存在的行

mysql - 使用多个表创建有效查询

database - 使用 "tree keys"在 Neo4j 中创建分层数据(树)结构

sql - 数据库设计 - 实体属性值 (EAV) 的替代方案

sql - 如何将线串分割成单独的线段?

sql - 联合操作后如何获取记录数..?