如何用一条SQL语句更新插入两个数据库表?
下面描述两个数据库表。星号突出显示主键。
+----------------+ +----------------+
| 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
如果您想以经典方式执行上述操作,请执行以下操作。
首先,我们可能同意
url
是一个自然主键。无论如何,您需要在该列中建立一个索引来加快查找速度:之后,如果您执行:
您最终会遇到两种情况:
•
INSERT
成功。这意味着您的$url
是新的,您可以继续:在这种情况下,
url_references
中新插入的行上的锁保证另一个线程将进入第二个场景(如果第一个场景)事务已成功提交(如果失败,则为第一种情况)。•
INSERT
失败。这意味着您的$url
已经已知,您可以继续:注意:第一个
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:After that if you execute:
you end up with two scenarios:
• The
INSERT
succeeds. That means your$url
is new and you can proceed with: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:Note: The first
INSERT
statement guarantees that racing condition onurl_references
table is correctly handled provided you have enabled a correct transaction isolation level andautocommit=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.您可以使用
REPLACE INTO
来避免在posts
表上选择INSERT/UPDATE
,然后根据受影响的行数进行选择REPLACE
确定是否需要INSERT到url_references中。像这样的事情:来自 MySQL
REPLACE
文档:请注意,我尚未测试上述伪代码,因此您可能需要对其进行调整。
请参阅: http://dev.mysql.com/doc/refman/5.0 /en/replace.html 供参考。
You can use
REPLACE INTO
to avoid deciding betweenINSERT/UPDATE
on theposts
table, then based on the number of rows affected byREPLACE
determine whether you need to INSERT into url_references. Something like this:From the MySQL
REPLACE
documentation: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.