PostgreSQL - 插入包含数组的复合类型数组

Mat*_*orm 5 sql postgresql perl dbi postgresql-9.1

我有一个包含 TEXT 数组等的复合类型。我在主表中使用它来创建复合类型的数组。
如何生成 INSERT 命令(不使用复合类型的默认字段名称)?我可以使用复合数组创建一个临时表,然后将其插入主表吗?

例如:

DROP TABLE collection;
DROP TABLE book_set;
DROP TYPE book;

CREATE TYPE book AS ( title TEXT, authors TEXT[], extra_spare TEXT );
CREATE TEMPORARY TABLE book_set ( books book[] );
CREATE TABLE shelf_collection ( shelf INT, position INT, books book[] );

-- Prefer to specify the fields I want, and NOT extra_spare as shown here!
-- AND it doesn't yet work... needs more casting?
INSERT INTO book_set( books ) VALUES (
      ( 'book1', array[ ( 'author1', 'author2' ) ], '' ),
      ( 'book2', array[ ( 'author3' )            ], '' ) ); 

-- And this obviously does not work yet!
INSERT INTO shelf_collection( shelf, position, books ) VALUES ( 1, 2, book_set ); 
Run Code Online (Sandbox Code Playgroud)

第一个 INSERT 失败并显示以下消息:

错误:INSERT 的表达式多于目标列。

无论有或没有 array[] 构造,都会失败。

我的实际使用情况要复杂得多,复合材料包含其他复合材料和许多领域。

出于性能原因,我没有在此处使用多个表(检索时不需要连接),并且内部复合材料和数组从不独立引用。

我正在使用perl(5.14.2)DBI(1.616)psql(9.1.7)


更多信息:

以下内容有效,但如何更改它以便我不需要指定书籍的所有字段:

DROP TABLE shelf_collection;
DROP TYPE book;

CREATE TYPE  book AS          ( title TEXT, authors TEXT[], extra_spare TEXT );
CREATE TABLE shelf_collection ( shelf INT, position INT, books book[] );

INSERT INTO shelf_collection VALUES ( 12, 23, array[ROW( 'book title 1', array[ 'author1', 'author2' ], '' )::book] );

SELECT * FROM shelf_collection;
Run Code Online (Sandbox Code Playgroud)

mvp*_*mvp 4

PostgreSQL 数组是有用的抽象(非标准,我应该补充一下),但它很容易被滥用 - 我认为这正是你想要做的。

您试图使用数组作为不规范化数据库模式的借口和捷径。它可能会与一些杂凑一起工作,但从长远来看这是不值得的。

如果继续使用数组,您将无法利用许多真正使 SQL 发挥作用的构造。例如,您无法有效地在book_set表中搜索任何给定的作者。

正确的设计应该是标准化——book_set不应该包含作者数组。相反,创建单独的表authors和单独的链接表book_author

诚然,使用规范化方法,插入数据会更加尴尬,查询数据也会更加尴尬 - 您将需要执行联接。

但是,它使得创建几乎任何可以想象到的查询成为可能。此外,通过适当的索引,即使您的数据集非常大,它也可以非常快地工作。

  • @MattGoldworm:为了呼应 mvp,你不应该害怕加入,甚至不应该害怕很多加入。关系数据库在设计时就考虑到了连接。如果您遇到性能问题,您应该首先考虑调整数据库,然后稍后(如果有的话)对数据进行非规范化。 (3认同)