【问题标题】:Updating an associative table in MySQL在 MySQL 中更新关联表
【发布时间】:2010-09-22 07:10:30
【问题描述】:

下面是我的(简化的)架构(在 MySQL 版本 5.0.51b 中)和我更新它的策略。必须有更好的方法。插入新项目需要 4 次访问数据库,编辑/更新项目最多需要 7

items:itemId、itemName
类别:catId、catName
地图:mapId*、itemId、catId
* mapId (varchar) 是 itemId + | 的 concat + 猫号

1) 如果插入:插入项目。通过 MySQL API 获取 itemId。
其他更新:只更新项目表。我们已经有了 itemId。

2) 有条件地批量插入categories

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

3) 从categories 中选择 ID。

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) 我们可能不再像更新前那样将类别与此项目相关联。删除此 itemId 的旧类别。

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

6) 如果我们将自己与某个类别分离,则可能我们将其孤立了。我们不想要没有项目的类别。因此,如果affected rows &gt; 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 步中找到的 ID。

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

请告诉我,我没有看到更好的方法。

【问题讨论】:

  • 是否涉及AUTO_INCREMENT 值?有些解决方案会快速“烧毁”它们。

标签: sql mysql database


【解决方案1】:

另外,如果您担心访问数据库,请在存储过程中执行步骤。那你就来一趟吧。

【讨论】:

  • 噢!你可以看出有人被困在 MySQL v3 领域太久了。我什至没有想到存储过程。好电话。
  • 有趣 - 我想在 4 中创建一个 proc,但它不起作用。我最终意识到它没有它们。我简直不敢相信。反正我觉得是4....
【解决方案2】:

您可以做很多事情来让工作变得更轻松:

  • 了解 [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

【讨论】:

    【解决方案3】:

    第 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');
    

    否则,您的解决方案非常标准,除非您想使用触发器来维护映射表。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-01-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多