3

我想用一条 sql 语句将标签添加到博客文章中。

假设我的表格如下所示:

tags
+-------+-----------+
| tagid | tag       |
+-------+-----------+
|     1 | news      | 
|     2 | top-story | 
+-------+-----------+

tag2post
+----+--------+-------+
| id | postid | tagid |     
+----+--------+-------+
|  0 |    322 |     1 |
+----+--------+-------+

我想解决的问题是插入一个新标签检索它的 id,然后在单个 sql 语句中将这个新 id 插入到关系表中。

INSERT INTO tag2post (postid, tagid)
VALUES
(
    332, # the post
    IF (
        (SELECT tagid FROM tags WHERE tag = 'new_tag'),
        (SELECT tagid FROM tags WHERE tag = 'new_tag'),
         # here is where i'd like to insert 
         # the new_tag and return it's id
        'i am lost here'
    )
)
4

5 回答 5

5

您不能将其作为单个插入来执行,因为插入是原子的——也就是说,在语句完成之前不会确定 ID。

将这两个语句包装在一个事务中,您将获得您的 ID 和原子性。

于 2009-01-26T15:06:52.613 回答
1

不要使用自动增量 ID 列,而是使用 GUID 列。然后,您可以在运行语句之前生成 GUID 并立即执行所有操作。

甚至Jeff Atwood 也喜欢这种方法,而且您不会因为使用 32 字符字符串而不是整数而显着降低速度。

此外,为了防止标签重复,您应该使用标签名称的 MD5 和作为标签 ID。

于 2009-01-26T15:13:41.883 回答
1

我认为你必须打破它。一种方法是将UNIQUE约束添加到tag并按如下方式进行:

INSERT IGNORE INTO tags (tag) VALUE ('new_tag')

接着

INSERT INTO tag2post (postid, tagid)
VALUES
(
    332, # the post
    (SELECT tagid FROM tags WHERE tag = 'new_tag')
)

INSERT IGNORE但是,可能无法很好地扩展。因此,另一种方法是SELECT,如果 id 不存在,那么如果另一个线程/进程/服务修改了您和现在INSERT之间的表,请务必在此处捕获异常。SELECTINSERT你做LAST_INSERT_ID()和 int 他抓住你重复最初的SELECT..

不太好,但如果并发是一个要求,你需要这样做。事务不会缓解这个问题,如果你对 没有UNIQUE约束tag,你最终可能会得到重复INSERT的 s。

于 2011-11-22T19:57:06.393 回答
0

您可以尝试这样做,如果无法选择它,则有效地进行插入,然后从插入的行中检索 LAST_INSERT_ID() ,但我严重怀疑它是否会起作用。

INSERT INTO tag2post (postid, tagid)
VALUES
(
    332, # the post
    IF (
        (SELECT tagid FROM tags WHERE tag = 'new_tag'),
        (SELECT tagid FROM tags WHERE tag = 'new_tag'),
        IF (
            (INSERT INTO tags (tag) VALUES ('new_tag')),
            LAST_INSERT_ID(),
            LAST_INSERT_ID()
        )
    )
)
于 2009-01-26T15:13:29.730 回答
0

如果您使用非自动增量字段并进行自己的增量计算,您可以在插入字段之前确定 id 是什么,并手动指定新的 id。

然后,您可以使用这些由 ;s 分隔的 id 为每个 tag2post 条目构建一个语句字符串,然后您可以将其发送到 msyql 执行。

于 2009-01-26T15:14:05.643 回答