вложенная вставка в MySQL для тегирования - PullRequest
3 голосов
/ 26 января 2009

Я хотел бы добавить тег к посту с помощью одного оператора SQL.

скажем, мои таблицы будут выглядеть следующим образом:

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

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

проблема, которую я хотел бы решить, это вставка нового тега , получение его идентификатора и затем вставка этого нового идентификатора в таблицу отношений одно заявление sql.

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 ]

5 голосов
/ 26 января 2009

Вы не можете сделать это как одну вставку, потому что вставки являются атомарными, то есть идентификатор не определяется до завершения инструкции.

Оберните оба заявления в транзакцию, и вы получите свой идентификатор и атомарность.

1 голос
/ 22 ноября 2011

Я думаю, тебе придется это разбить. Один из способов сделать это - добавить ограничение 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, если идентификатор отсутствует, INSERT, тогда обязательно поймайте исключение здесь, если другой поток / процесс / служба изменил таблицу между вашим SELECT и сейчас. В INSERT вы делаете LAST_INSERT_ID(), и он ловит вас, повторяя начальный SELECT ..

Не круто, но если требуется параллелизм, вам нужно это сделать. Транзакции не устранят проблему, и если у вас нет ограничения UNIQUE на tag, вы можете получить дубликат INSERT s.

1 голос
/ 26 января 2009

Вместо использования столбца идентификатора с автоинкрементом используйте столбец GUID. Затем вы можете сгенерировать GUID, прежде чем запускать оператор и делать все сразу.

Даже Джеффу Этвуду нравится такой подход , и вы не получите значительного снижения скорости за использование 32-символьных строк вместо целых.

Кроме того, для предотвращения дублирования тегов вы должны использовать сумму MD5 имени тега в качестве идентификатора тега.

0 голосов
/ 26 января 2009

Если вы используете неавтоматическое поле приращения и выполняете свой собственный расчет приращения, вы можете определить, каким будет идентификатор перед вставкой поля, и вручную указать новые идентификаторы.

Затем вы можете создать строку операторов для каждой записи tag2post, используя эти идентификаторы, разделенные; s, и вы можете отправить ее в msyql для выполнения.

0 голосов
/ 26 января 2009

Вы можете попробовать это, эффективно выполнив вставку, если она не может выбрать ее, а затем извлекая 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()
        )
    )
)
...