【问题标题】:INSERT into table with array of composite type插入到具有复合类型数组的表中
【发布时间】:2015-03-26 06:55:04
【问题描述】:

因此,我尝试将临时表中的值复制到具有数组类型的表中,但出现以下错误,我找不到解决方法。

ERROR:  cannot assign to field "addressid" of column "address" because its type addresstype[] is not a composite type
LINE 32: ...nID,Person.Title,Person.FirstName,Person.LastName,Person.Add...
                                                              ^
********** Error **********

ERROR: cannot assign to field "addressid" of column "address" because its type addresstype[] is not a composite type
SQL state: 42804

这是我尝试的查询:

INSERT INTO Customer (CustomerID,Person.PersonID,Person.Title,Person.FirstName,Person.LastName,Person.Address.AddressID,Person.Address.AddressLine1,Person.Address.AddressLine2,Person.Address.City,Person.Address.PostalCode)
SELECT TCustomer.CustomerID,TPerson.PersonID,TPerson.Title,TPerson.FirstName,TPerson.LastName,TAddress.AddressID,TAddress.AddressLine1,TAddress.AddressLine2,TAddress.City,TAddress.PostalCode
FROM TCustomer,TPerson,TPersonAddress,TAddress
WHERE TCustomer.PersonID = TPerson.PersonID
AND TPerson.PersonID = TPersonAddress.PersonID
AND TPersonAddress.AddressID = TAddress.AddressID;

表格和类型:

CREATE TYPE AddressType AS(
AddressID integer,
AddressLine1 text,
AddressLine2 text,
City text,
PostalCode text);

CREATE TYPE PersonType AS(
PersonID integer, 
Title text,
FirstName text,
LastName text,
Address AddressType[]);

CREATE TABLE Customer(
CustomerID integer,
Person PersonType,
PRIMARY KEY(CustomerID));

CREATE TEMPORARY TABLE TAddress (AddressID integer,AddressLine1 text,AddressLine2 text,City text,PostalCode text);
CREATE TEMPORARY TABLE TPerson (PersonID integer,Title text,FirstName text,LastName text);
CREATE TEMPORARY TABLE TCustomer (CustomerID integer,PersonID integer);
CREATE TEMPORARY TABLE TPersonAddress (PersonID integer,AddressID integer);

临时表已从 CSV 文件复制数据。 问题是每个人可以有许多不同的地址。 所以我必须将所有地址加载到 AddressType 数组中。 但现在这似乎是不可能的,我找不到处理数组的方法。

我在互联网上找到的所有处理数组的方法是:

INSERT INTO aa VALUES (3, ARRAY[ARRAY[1,2],ARRAY[3,4]]);
INSERT INTO sal_emp
    VALUES ('Bill',
    '{10000, 10000, 10000, 10000}',
    '{{"meeting", "lunch"}, {"training", "presentation"}}');

这样,但这些示例只是添加了对我的情况完全没有帮助的指定值。那么如何让它从以下位置复制值: TAddress.AddressID,TAddress.AddressLine1,TAddress.AddressLine2,TAddress.City,TAddress.PostalCode

到数组:

Person.Address.AddressID,Person.Address.AddressLine1,Person.Address.AddressLine2,Person.Address.City,Person.Address.PostalCode

如果是同一个人,则必须将所有地址添加到同一个数组中。

【问题讨论】:

  • 您可以随意改进表格布局吗?因为我要推荐database normalization
  • 是的,我会考虑任何建议。尽管请注意,重点是使关系数据库成为对象关系数据库。所以我不想拆分表太多以至于我最终得到相同的关系数据库模式。我知道对象关系数据库很糟糕,但你能做什么,我需要这样做。(临时表是什么关系数据库表看起来像我猜你可以找出 pkeys/fkeys)
  • 我想至少跳过表 PersonAddress,包括类型/数组等,因此它与关系数据库有所不同。
  • 你提供的链接主要讲的是关系模型。
  • 我不同意,复合类型的数组是合理且有用的选择,因为行只是向量集。

标签: arrays postgresql database-design insert object-relational-model


【解决方案1】:

关于错误

虽然可以像这样分配复合/行类型的子字段:

CREATE TYPE foo AS (a int, b text);
CREATE TABLE bar (c int, f foo);

两者都有效:

INSERT INTO bar(a,b) SELECT 1, '(1,foo)';
INSERT INTO bar(a,b.a, b.b) SELECT 2, 2, 'bar';

数组也是不可能的(所以对于复合类型的数组也不可能)。

CREATE TABLE baz (a int, b <b>foo[]</b>);

不可能:

<strike>INSERT INTO baz(a,b.a, b.b) SELECT 2, 2, 'bar';</strike>

必须是以下之一:

INSERT INTO baz(a,b) SELECT 1, <b>'{"(1,foo)"}'</b>;
INSERT INTO baz(a,b) SELECT 1, <b>ARRAY['(1,foo)']</b>;

数据库设计

我将建议完全重新设计标准化表格。

复合类型的数组非常笨拙,不节省任何磁盘空间,禁用了许多用于索引或关系完整性的核心功能,并且确实是 Postgres 提供的选项的一种奇特用途。

我会使用复合列类型。我知道你评论说你“需要”这样做,但我不明白这一点。仅仅因为你可以做到,并不意味着它应该做到。改用或多或少的规范化表。两个表的简单案例:

CREATE TABLE person (
  person_id serial PRIMARY KEY
, title text
, firstname text
, lastname text
);

CREATE TABLE address (
  address_id serial PRIMARY KEY
, person_id int REFERENCES person
, addressline1 text
, addressline2 text
, city text
, postalcode text
);

一个人可以有多个地址,一个地址属于一个person。实际上,地址由多个人使用,但冗余添加几个地址通常更简单。如果您有很多这样的情况,请使用带有附加表person_address 的多对多实现。详情在这里:

【讨论】:

  • 我想出了一个更好的解决方案:Person -> table 指的是 PersonAddress -> table 有类型(而不是地址 ID)地址。不需要数组,仍然有 OR-database 元素你怎么看?
  • @DieCriminal:我添加了一些关于数据库设计的内容。
【解决方案2】:

至少在 PostgreSQL 10 上,您可以这样做:

CREATE TYPE Child AS ( Name VARCHAR(10), Age INTEGER );

CREATE TABLE Father ( Name VARCHAR(10), Children Child[] );

INSERT INTO Father(Name, Children) VALUES (
    'Thanos',
    ARRAY[
        ('Nebula', 25)::Child,
        ('Gamora', 28)::Child
    ]
)

此解决方案的优点在于,如果您的 TYPE 中有 VARCHAR,则无需处理转义序列。

【讨论】:

    猜你喜欢
    • 2014-04-23
    • 1970-01-01
    • 1970-01-01
    • 2012-08-09
    • 1970-01-01
    • 2022-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多