我正在尝试使用PostgreSQL数据库在PHP中开发Q& A网站。 我有一个动作来创建一个页面,其中包含标题,正文,类别和标签。我设法插入所有这些字段,但是我在插入多个标记值时遇到了一些问题。
我使用这个函数将逗号分隔的值放到一个数组中,现在我想要一些东西将每个数组元素插入到表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的新手,我正在努力解决一些新概念。
答案 0 :(得分:2)
您可以使用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 DISTINCT
中删除input_tags
。
详细解释:
如果您有并发写入,则可能需要执行更多操作。特别考虑第二个链接。