多个 INSERTS 到一个表和多对多表

Posted

技术标签:

【中文标题】多个 INSERTS 到一个表和多对多表【英文标题】:Multiple INSERTS into one table and many to many table 【发布时间】:2017-09-04 03:12:55 【问题描述】:

我正在尝试使用 PostgreSQL 数据库在 php 中开发一个问答网站。 我有一个动作来创建一个具有标题、正文、类别和标签的页面。我设法插入了所有这些字段,但是在插入多个标签值时遇到了一些问题。

我使用这个函数将逗号分隔的值放入一个数组中,现在我想要将每个数组元素插入到表 tags 上的数据库中(避免重复),然后插入我的多对多关系表 @ 987654323@:

$tags = explode(',', $_POST['tags']); //Comma separated values to an array

打印如下内容:

Array ( [0] => hello [1] => there [2] => this [3] => is [4] => a [5] => test )

action/create_question.php

$category = get_categoryID_by_name($_POST['category']);

$question = [
    'userid' => auth_user('userid'),
    'body' => $_POST['editor1'],
    'title' => $_POST['title'],
    'categoryid' => $category
];

create_question($question, $tags);

然后是我的create_question 我应该在其中插入标签。

function create_question($question, $tags) 

    global $conn;
    $query_publications=$conn->prepare("SELECT * FROM insert_into_questions(:body, :userid, :title, :categoryid);
");
    $query_publications->execute($question);

我正在考虑做这样的事情:

全局 $conn;

foreach ($tags as $tag) 

    $query_publications=$conn->prepare("INSERT INTO tags(name) VALUES($tag);
");
    $query_publications->execute($question);    

但是我需要将标签 id 插入到我的多对多表中。我是否需要创建另一个过程 get_tags_id 然后获取一个 tag_id 数组并在我尝试标记时插入它们? 我什么时候执行查询?在两个插入之后还是在彼此的末尾?

对于任何误用的术语或我的新手问题,我们深表歉意。我是 PHP 新手,正在为一些新概念而苦苦挣扎。

【问题讨论】:

您需要在 questions 表和 tags 表上有一个主键 (ID)。然后有第三个表只包含问题和标签 ID。 我有。我省略了这一点,因为我使用这种方法的问题很清楚 插入后,您可以使用 PDO 的 lastInsertId 函数来检索您刚刚插入的行的主键。然后,您可以将数据添加到下一个表中,而无需先执行单独的查询来获取主键。 php.net/manual/en/pdo.lastinsertid.php 如果您提供实际的表定义(CREATE TABLE 语句)和您的 Postgres 版本,这将有助于 很多。您只需要一个单个 SQL 语句。 那么你有答案了吗? 【参考方案1】:

您可以在一个使用 CTE 的 SQL 命令中完成所有操作。

假设 Postgres 9.6 和这个经典的多对多模式(因为你没有提供它):

CREATE TABLE questions (
  question_id serial PRIMARY KEY
, title text NOT NULL
, body text
, userid int
, categoryid int
);

CREATE TABLE tags (
  tag_id serial PRIMARY KEY
, tag text NOT NULL UNIQUE);

CREATE TABLE questiontags (
  question_id int REFERENCES questions
, tag_id      int REFERENCES tags
, PRIMARY KEY(question_id, tag_id)
);

要插入带有标签数组单个问题

WITH input_data(body, userid, title, categoryid, tags) AS (
   VALUES (:title, :body, :userid, :tags)
   )
 , input_tags AS (                         -- fold duplicates
      SELECT DISTINCT tag
      FROM   input_data, unnest(tags::text[]) tag
      )
 , q AS (                                  -- insert question
   INSERT INTO questions
         (body, userid, title, categoryid)
   SELECT body, userid, title, categoryid
   FROM   input_data
   RETURNING question_id
   )
 , t AS (                                  -- insert tags
   INSERT INTO tags (tag)
   TABLE  input_tags  -- short for: SELECT * FROM input_tags
   ON     CONFLICT (tag) DO NOTHING        -- only new tags
   RETURNING tag_id
   )
INSERT INTO questiontags (question_id, tag_id)
SELECT q.question_id, t.tag_id
FROM   q, (
   SELECT tag_id
   FROM   t                                -- newly inserted
   UNION  ALL
   SELECT tag_id
   FROM   input_tags JOIN tags USING (tag) -- pre-existing
   ) t;

dbfiddle here

这会即时创建任何尚不存在的标签。

Postgres 数组 的文本表示形式如下所示:tag1, tag2, tag3

如果保证输入数组有不同的标签,您可以从 CTE input_tags 中删除 DISTINCT

详细解释

Insert data in 3 tables at a time using Postgres How to use RETURNING with ON CONFLICT in PostgreSQL? How to implement a many-to-many relationship in PostgreSQL? Cannot INSERT: ERROR: array value must start with "" or dimension information

如果您有并发写入,您可能需要做更多。特别考虑第二个链接。

【讨论】:

以上是关于多个 INSERTS 到一个表和多对多表的主要内容,如果未能解决你的问题,请参考以下文章

十一 .Django 多对多表ManyToManyField (ORM)

SQL - 从一个表中选择,同时在另外两个表之间进行内部连接(多对多表和另一个表)

多对多表的设计小案例

简述数据库设计中一对多和多对多的应用场景?

Django中ORM多对多表的操作

Hibernate多表关系配置——多对多对关系映射