Обновление ассоциативной таблицы в MySQL - PullRequest
1 голос
/ 14 ноября 2008

Ниже приведена моя (упрощенная) схема (в версии MySQL 5.0.51b) и моя стратегия ее обновления. Должен быть лучший способ. Для вставки нового элемента требуется 4 поездки в базу данных, а редактирование / обновление элемента занимает до 7 !

items : itemId, itemName
категорий : catId, catName
map : mapId *, itemId, catId
* mapId (varchar) является константой itemId + | + catId

1) При вставке: вставить элемент. Получить itemId через MySQL API.
Другое обновление: просто обновите таблицу предметов. У нас уже есть itemId.

2) Условно пакетная вставка в categories.

INSERT IGNORE INTO categories (catName)
VALUES ('each'), ('category'), ('name');

3) Выберите идентификаторы из categories.

SELECT catId FROM categories
WHERE catName = 'each' OR catName = 'category' OR catName = 'name';

4) Условно пакетная вставка в map.

INSERT IGNORE INTO map (mapId, itemId, catId)
VALUES ('1|1', 1, 1), ('1|2', 1, 2), ('1|3', 1, 3);

Если вставить: мы закончили. Остальное обновление: продолжение.

5) Возможно, мы больше не связываем категорию с этим элементом, который мы делали до обновления. Удалить старые категории для этого элементаId.

DELETE FROM MAP WHERE itemId = 2
AND catID <> 2 AND catID <> 3 AND catID <> 5;

6) Если мы отмежевались от категории, возможно, мы оставили ее сиротой. Мы не хотим категории без предметов. Поэтому, если affected rows > 0, убейте потерянные категории. Я не нашел способа объединить их в MySQL, так что это # ​​6 и # 7.

SELECT categories.catId
FROM categories
LEFT JOIN map USING (catId)
GROUP BY categories.catId
HAVING COUNT(map.catId) < 1;

7) Удалить идентификаторы, найденные на шаге 6.

DELETE FROM categories
WHERE catId = 9
  AND catId = 10;

Пожалуйста, скажите мне, что есть лучший способ, которого я не вижу.

Ответы [ 3 ]

2 голосов
/ 14 ноября 2008

Есть несколько вещей, которые вы можете сделать, чтобы немного упростить:

  • Читать о [INSERT...ON DUPLICATE KEY UPDATE] [1]

  • Удалите старые категории, прежде чем вставлять новые категории. Это может принести пользу от индекса лучше.

    DELETE FROM map WHERE itemId=2;

  • Возможно, вам не нужно map.mapID. Вместо этого объявите составной первичный ключ над (itemID, catID).

  • Как сказал Питер в своем ответе, используйте удаление из нескольких таблиц MySQL:

    DELETE categories.* FROM categories LEFT JOIN map USING (catId) 
    WHERE map.catID IS NULL
    

    http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html

2 голосов
/ 14 ноября 2008

Также, если вы беспокоитесь о поездках в БД, сделайте шаги в хранимую процедуру. Тогда у вас есть одна поездка.

1 голос
/ 14 ноября 2008

Шаги 6 и 7 можно комбинировать достаточно легко:

DELETE categories.*
FROM categories
LEFT JOIN map USING (catId)
WHERE map.catID IS NULL;

Шаги 3 и 4 также можно комбинировать:

INSERT IGNORE INTO map (mapId, itemId, catId)
    SELECT CONCAT('1|', c.catId), 1, c.catID
    FROM categories AS c
    WHERE c.catName IN('each','category','name');

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...