Luí*_*sta 6 php database postgresql upsert common-table-expression
我正在尝试使用 PostgreSQL 数据库在 PHP 中开发一个问答网站。我有一个操作来创建一个具有标题、正文、类别和标签的页面。我设法插入了所有这些字段,但是在插入多个标签值时遇到了一些问题。
我使用这个函数将逗号分隔的值放入一个数组中,现在我想要将每个数组元素插入到表上的数据库中(避免重复),tags然后插入到我的多对多关系表中questiontags:
$tags = explode(',', $_POST['tags']); //Comma separated values to an array
它打印出这样的东西:
Array ( [0] => hello [1] => there [2] => this [3] => is [4] => a [5] => test )
动作/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 新手,并且正在为一些新概念而苦苦挣扎。
可以使用 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)  -- all input here
   )
 , 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;
db<>在这里摆弄
这将创建任何即时不存在的标签。
这是一个数组文字(Postgres 数组的文本表示形式:
'{tag1, tag2, tag3}'
如果保证输入数组具有不同的标签,请DISTINCT从 CTE 中删除input_tags。
详细解释:
如果可以并发写入,请考虑:
| 归档时间: | 
 | 
| 查看次数: | 1376 次 | 
| 最近记录: |