如何用一条SQL语句更新插入两个数据库表?

发布于 2024-11-30 10:09:51 字数 1157 浏览 6 评论 0原文

下面描述两个数据库表。星号突出显示主键。

+----------------+    +----------------+
| posts          |    | url_references |
+----------------+    +----------------+
| id*            |    | url*           |
| post_content   |    | post_id        |
+----------------+    +----------------+

我想根据表中是否存在相应条目来插入更新帖子 url_references。达到此目的的最佳SQL 命令组合是什么?我想避免PHP中处理有关插入更新的决定。
以下场景描述了使用 PHP 命令的替代分步行为。

SELECT * FROM url_references WHERE url = $url;

场景 1:插入新条目。

// mysql_num_rows() returns 0
INSERT INTO post (post_content) VALUES ($postContent);
$postId = mysql_insert_id();
INSERT INTO url_references (url, post_id) VALUES ($url, $postId);

场景 2:更新现有条目。

// mysql_num_rows() returns 1
$row = mysql_fetch_array($rows);
$postId = $row['post_id'];
UPDATE posts SET post_content = $postContent WHERE id = post_id;

编辑1:请注意,我无法直接检查帖子中的id!我想根据 url 作为主键来管理(插入/更新)帖子

There are two database tables described in the following. The asterisk highlights the primary keys.

+----------------+    +----------------+
| posts          |    | url_references |
+----------------+    +----------------+
| id*            |    | url*           |
| post_content   |    | post_id        |
+----------------+    +----------------+

I want to insert or update a post based on the existence of the corresponding entry in the table url_references. What is the best combination of SQL commands to reach this? I would like to avoid to process the decision about insert or update in PHP.
The following scenarios describe the alternative step by step behavior using PHP commands.

SELECT * FROM url_references WHERE url = $url;

Scenario 1: Insert new entry.

// mysql_num_rows() returns 0
INSERT INTO post (post_content) VALUES ($postContent);
$postId = mysql_insert_id();
INSERT INTO url_references (url, post_id) VALUES ($url, $postId);

Scenario 2: Update existing entry.

// mysql_num_rows() returns 1
$row = mysql_fetch_array($rows);
$postId = $row['post_id'];
UPDATE posts SET post_content = $postContent WHERE id = post_id;

Edit 1: Note, that I cannot check for the id in posts directly! I want to manage (insert/update) posts based on their url as the primary key.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

九八野马 2024-12-07 10:09:52

如果您想以经典方式执行上述操作,请执行以下操作。

首先,我们可能同意 url 是一个自然主键。无论如何,您需要在该列中建立一个索引来加快查找速度:

CREATE UNIQUE INDEX url_references_idx ON url_references(url);

之后,如果您执行:

INSERT INTO url_references (url) VALUES ($url);

您最终会遇到两种情况:

INSERT 成功。这意味着您的 $url 是新的,您可以继续:

INSERT INTO posts (id, post_content) values (NULL, $postContent);
SELECT LAST_INSERT_ID(); // This will return $post_id
UPDATE url_references SET post_id = $post_id WHERE url = $url;
COMMIT;

在这种情况下,url_references 中新插入的行上的锁保证另一个线程将进入第二个场景(如果第一个场景)事务已成功提交(如果失败,则为第一种情况)。

INSERT 失败。这意味着您的 $url 已经已知,您可以继续:

SELECT post_id FROM url_references WHERE url = $url;
UPDATE posts SET post_content = $postContent WHERE id = $post_id;
COMMIT;

注意:第一个 INSERT 语句保证 url_references 表上的赛车条件正确如果您已启用正确的事务隔离级别和 autocommit=off,则已处理。

注意:在这种情况下使用 SELECT ... FOR UPDATE 不起作用,因为它只会锁定现有行(并且我们需要锁定即将插入的不存在行)。抱歉,如果我让您感到困惑,请忽略我在您的问题下的评论。

If you would like to do above in a classical way, do the following.

First we may agree that url is a natural primary key. Anyway you need an index in this column to speedup your lookups:

CREATE UNIQUE INDEX url_references_idx ON url_references(url);

After that if you execute:

INSERT INTO url_references (url) VALUES ($url);

you end up with two scenarios:

• The INSERT succeeds. That means your $url is new and you can proceed with:

INSERT INTO posts (id, post_content) values (NULL, $postContent);
SELECT LAST_INSERT_ID(); // This will return $post_id
UPDATE url_references SET post_id = $post_id WHERE url = $url;
COMMIT;

In this scenario the lock on newly inserted row in url_references guarantees that another thread will go the 2nd scenario, if 1st transaction is successfully committed (or 1st scenario if it fails).

• The INSERT fails. That means your $url is already known and you can proceed with:

SELECT post_id FROM url_references WHERE url = $url;
UPDATE posts SET post_content = $postContent WHERE id = $post_id;
COMMIT;

Note: The first INSERT statement guarantees that racing condition on url_references table is correctly handled provided you have enabled a correct transaction isolation level and autocommit=off.

Note: Using SELECT ... FOR UPDATE does not work in this case, as it will lock only existing rows (and we need to lock non-existing row, which is about to be inserted). Sorry if I confused you, please ignore my comment under your question.

贱贱哒 2024-12-07 10:09:52

您可以使用 REPLACE INTO 来避免在 posts 表上选择 INSERT/UPDATE,然后根据受 影响的行数进行选择REPLACE 确定是否需要INSERT到url_references中。像这样的事情:

$sql = "REPLACE INTO posts (post_id, post_content) VALUES ($postId, $postContent)";
$result = mysql_query($sql);
$numRows = mysql_num_rows($result);

if ($numRows == 1) {
    // was INSERT not DELETE/INSERT (UPDATE) - need to insert into url_references

    $postId = mysql_insert_id();
    $sql = "INSERT INTO url_references (url, post_id) VALUES ($url, $postId)";

    ... do SQL INSERT etc
}

来自 MySQL REPLACE 文档:

REPLACE 语句返回一个计数来指示行数
做作的。这是删除和插入的行的总和。如果
单行 REPLACE 的计数为 1,插入了一行但没有行
被删除了。如果计数大于 1,则显示一个或多个旧行
在插入新行之前被删除。

请注意,我尚未测试上述伪代码,因此您可能需要对其进行调整。

请参阅: http://dev.mysql.com/doc/refman/5.0 /en/replace.html 供参考。

You can use REPLACE INTO to avoid deciding between INSERT/UPDATE on the posts table, then based on the number of rows affected by REPLACE determine whether you need to INSERT into url_references. Something like this:

$sql = "REPLACE INTO posts (post_id, post_content) VALUES ($postId, $postContent)";
$result = mysql_query($sql);
$numRows = mysql_num_rows($result);

if ($numRows == 1) {
    // was INSERT not DELETE/INSERT (UPDATE) - need to insert into url_references

    $postId = mysql_insert_id();
    $sql = "INSERT INTO url_references (url, post_id) VALUES ($url, $postId)";

    ... do SQL INSERT etc
}

From the MySQL REPLACE documentation:

The REPLACE statement returns a count to indicate the number of rows
affected. This is the sum of the rows deleted and inserted. If the
count is 1 for a single-row REPLACE, a row was inserted and no rows
were deleted. If the count is greater than 1, one or more old rows
were deleted before the new row was inserted.

Note that I haven't tested the above pseudo-code, so you may have to tweak it.

See: http://dev.mysql.com/doc/refman/5.0/en/replace.html for reference.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文