【问题标题】:PostgreSQL - INSERT an array of composite type containing arraysPostgreSQL - 插入包含数组的复合类型数组
【发布时间】:2013-01-08 22:48:35
【问题描述】:

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

例如:

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 ); 

第一个 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;

【问题讨论】:

  • 欢迎来到 StackOverflow!在这一点上,您似乎还没有达到使用 Perl DBI 的地步,所以这确实是一个 PostgreSQL 问题,对吧?如果您不使用array types,SQL 是否有效?
  • 哦。当您说“它还不起作用”时,您是否有错误消息?你可以复制它并粘贴到问题中吗?
  • 在我了解复合类型之前,我已经完成了整个解决方案。但是做复合材料的插入,特别是包含数组的堆肥数组让我感到困惑。错误信息是:ERROR: INSERT has more expressions than target columns
  • 如果我删除 array[] 构造,仍然会失败并显示相同的错误消息。
  • 现在有一个工作示例,但仍有一个问题:我该如何解决它,所以我不需要指定 book 的所有字段,因为我的真实代码在复合中有很多字段.

标签: sql perl postgresql postgresql-9.1 dbi


【解决方案1】:

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

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

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

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

当然,使用规范化方法插入数据更尴尬,查询数据也更尴尬 - 您需要执行连接。

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

【讨论】:

  • 感谢 mvp。我理解你的回应。但是,在我的实际情况中,出于性能原因,我真的不想要单独的表。一旦我从主表中执行 SELECT,我需要数组在那里,而不必使用额外的关联 I/O 进行 JOINS。我知道数组中的数据将不可搜索,但这不是问题。大部分数据已经从其他表中复制,并且为了提高性能而存在(复制)。
  • 您可能没有意识到,但是如果您的数组大于某个阈值,Postgres 将不得不将您的数据卸载到不可见的 TOAST 表中(该表被分成固定大小的块并与主表连接)。这是相同的加入,但没有你控制它。做真正的连接——如果你做对了,它们不一定很慢
  • PS:我从一个标准化数据库开始,但最终使用 9 个 JOINS 来获取我主要的高容量查询的数据。
  • PPS:数组一般只有1个条目...偶尔2-3个
  • @MattGoldworm:为了呼应 mvp,你不应该害怕加入,甚至不应该害怕加入。关系数据库在设计时就考虑到了连接。如果您遇到性能问题,您应该首先考虑调整您的数据库,然后再过一段时间(如果有的话)对您的数据进行非规范化。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-06-19
  • 1970-01-01
  • 2015-03-26
  • 1970-01-01
  • 1970-01-01
  • 2022-10-20
  • 2017-07-05
相关资源
最近更新 更多