当父 table 的值都存储在一个数组中时,如何执行数组插入到联结点 table 中?

How do I perform an array insert into a junction table when the parent tables' values are all stored into an array?

我正在使用 postgresql。 所以,假设我有 3 tables.

CREATE TABLE article (
article_id BIGSERIAL,
article_name VARCHAR(20),
PRIMARY KEY(article_id)
);

CREATE TABLE tags (
tag_id VARCHAR(30)[] NOT NULL
PRIMARY KEY(tag_id)
);

和交界处table:

CREATE TABLE article_tags (
tag_id VARCHAR(10) NOT NULL,
article_id INTEGER NOT NULL,
FOREIGN KEY(tag_id) REFERENCES tags(tag_id) ON UPDATE CASCADE ON DELETE CASCADE,
FOREIGN KEY(article_id) REFERENCES article(article_id) ON DELETE CASCADE ON UPDATE CASCADE,
PRIMARY KEY (article_id, tag_id)

所以在我的标签中 table 我有一个条目,它是所有可能标签的数组,即

tag_id
______
{tag1,tag2,tag3,tag4}

当我尝试在任何 individual/combinations 标签的 article_tags 中执行插入时,即(假设存在 ID 为 1 的文章)

INSERT INTO article_tags (article_id, tag_id) VALUES (1, '{tag4}');
OR
INSERT INTO article_tags (article_id, tag_id) VALUES (1, '{tag4, tag3}');

我遇到错误

ERROR:  insert or update on table "article_tags" violates foreign key constraint "article_tags_tag_id_fkey"
DETAIL:  Key (tag_id)=({tag4}) is not present in table "tags". / DETAIL:  Key (tag_id)=({tag4, tag3}) is not present in table "tags".

有没有办法让插入考虑主键数组(tag_id)中的所有值来执行插入?如果是由于 table 结构错误,是否有更好的方法来构建 table 以便我能够将标签的任何值插入标签中存在的 article_tags( tag_id) 的数组,而不将所有可能的标签排列插入到标签 (tag_id) 中,这将花费相当多的时间,但可以正常工作。

如果我恰好插入那个数组,它会起作用

INSERT INTO article_tags (article_id, tag_id) VALUES (1, '{tag1,tag2,tag3,tag4}');

但除非需要,否则我不希望创建标签的每一个排列。

您需要规范化结构,其中每个标签都有自己的行;正如您所说的那样,您有“事先”。 Postgres 提供了 functions dealing with arrays 名副其实的聚宝盆(很多)。要将文章附加到您想要 UNNEST 的数组中的每个标签,要重建 文章,标签数组 结构使用 ARRAY AGG.

  insert into article_tags(article_id, tag_id) 
     select a.article_id, t.tag_id
       from (select article_id
               from article
              where article_name = <article name> 
             ) a
      cross join (select tag_id 
                    from tags 
                   where tag_name in (select unnest ( <tags array >)) 
                 ) t 
      on conflict (article_id, tag_id) do nothing ; 

--- 重建 Article_Name, Tag_Array

select a.article_name, array_agg(t.tag_name order by t.tag_name) 
  from article_tags  ats 
  join article       a  on (a.article_id = ats.article_id)
  join tags          t  on (t.tag_id = ats.tag_id)
 group by article_name;

请参阅 example here 了解如何使用它们。该示例构建了一个存储过程来处理同时在 3 个表中创建条目。但是其中的语句可以 运行 独立地对参数传递进行微小的修改。