views:

533

answers:

4

hi all,

i'd like to add a tag to a blogpost with a single sql statement.

say my tables would look as follows:

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

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

the problem i'd like to solve is inserting a new tag, retrieve it's id and then inset this new id into the relation table in a single sql statement.

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'
    )
)
+5  A: 

You can't do this as a single insert because inserts are atomic--that is, the ID isn't determined until the statement completes.

Wrap both statements in a transaction and you will get your ID, and atomicity.

Michael Haren
Recent mysql releases can do stored procedures, so I'd say this is the perfect spot for one: InsertOrCreateTag(@TagName), returns tag ID.
Tomalak
A: 

You could try this, effectively doing an insert if it couldn't select it, and then retrieving the LAST_INSERT_ID() from the inserted row, but I seriously doubt it will work.

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()
        )
    )
)
Seldaek
tried it and it failed ... but thx ;)
Pierre Spring
+1  A: 

Instead of using an auto-increment ID column, use a GUID column. Then you can generate the GUID before you run the statement and do everything at once.

Even Jeff Atwood likes this approach, and you don't get a significant speed penalty for using 32-char strings instead of integers.

Also, to prevent tag duplication you should use the MD5 sum of the tag name as the tag ID.

Jason Cohen
+1. And if even Jeff Atwood likes it, it must be the blessed way. :-D
Tomalak
ehhh ... you replace the tagid by the md5(tagid, tag)? isn't there some strange recursion that could break the universe?
Pierre Spring
No, you replace the tagid by md5(tag). Since there's no other data in the table, and since reusing rows works fine for queries, there's no reason to have an additional ID column.
Jason Cohen
A: 

If you use a non-auto increment field and do your own increment calculation, you can determine what the id will be before you insert the field, and specify the new ids manually.

Then you can build a string of statements for each tag2post entry using these ids seperated by ;s and you can send it to msyql to execute.

Alpants