【问题标题】:How to combine all these MySQL queries into one?如何将所有这些 MySQL 查询合二为一?
【发布时间】:2012-08-14 03:51:10
【问题描述】:

我有很多带有“狗”标签的文章。我现在有一个名为“猫”的新标签。我想将标签“猫”添加到所有已经有标签“狗”的文章中。一些文章有这两个标签。我不想用“猫”重新标记这些。

换句话说,如果一篇文章有​​标签“狗”但还没有标签“猫”,我想给它添加标签“猫”。这是我写的脚本:

<?php 

    # Get "cat" tag id
    $sql = "SELECT `id`
            FROM tags
            WHERE name = 'cat'
            LIMIT 1";

    $cat_tag = mysql_fetch_assoc(mysql_query($sql));

    # Get "dog" tag id
    $sql = "SELECT `id`
            FROM tags
            WHERE name = 'dog'
            LIMIT 1";

    $dog_tag = mysql_fetch_assoc(mysql_query($sql));

    ######################################

    # Get all nodes tagged with "dog"   
    $sql = "SELECT `node_id`
            FROM node_tags
            WHERE `tag_id` = '" . $dog['id'] . "'";

    $query = mysql_query($sql);
    while($row = mysql_fetch_assoc($query)) {

        # Check to see if current node has "cat" tag already    
        $sql = "SELECT COUNT(*)
                FROM node_tags
                WHERE `node_id` = '" . $row['node_id'] . "'         
                AND `tag_id` = '" . $cat['id'] . "'";


        $check_already_exists = mysql_fetch_assoc(mysql_query($sql));

        # If node doesn't already have "cat" tag, then add it
        if($check_already_exists == '0') {
            $sql = "INSERT INTO `node_tags`(node_id, tag_id) 
                    VALUES('" . $row['node_id'] . "', '" . $cat['id'] . "')";
            mysql_query($sql);
        }
    }

?>

我希望能够直接从我的 MySQL 管理器工具中运行它。所以它不能有任何 PHP,但应该是一个大型 SQL 查询。如何做到这一点?

【问题讨论】:

    标签: php mysql sql


    【解决方案1】:

    首先更改您的表并将(node_id 和 tag_id)一起设为 UNIQUE,因为这似乎是您需要的。

    ALTER TABLE `node_tags` ADD UNIQUE (`node_id`,`tag_id`);
    

    这是您的查询:

    $sql = "INSERT IGNORE INTO `node_tags`  
            SELECT (SELECT `node_id` FROM node_tags WHERE EXISTS (SELECT tags.* FROM tags WHERE node_tags.`tag_id` = tags.`id` AND tags.name = 'dog') LIMIT 1),
                   (SELECT `id` FROM tags WHERE name = 'cat' LIMIT 1)";
    

    【讨论】:

      【解决方案2】:

      试试这个查询。我没有测试过这个。但我认为这会奏效。

      INSERT into node_tags(node_id, tag_id)
      ( SELECT node_id, tag_id
       FROM node_tags nt , tags t
       where t.id = nt.tag_id AND t.name = 'dog' 
       AND nt.node_id NOT IN (SELECT t1.id FROM node_tags nt1, tags t1
       where nt1.node_id = nt.node_id  AND t1.id = nt1.tag_id AND t1.name = 'cat')
      )
      

      【讨论】:

        【解决方案3】:

        您可以根据 select 子句进行插入:

        INSERT INTO node_tags (node_id, tag_id)
        SELECT node_id, (SELECT MAX(id) FROM tags WHERE name = 'cat') 
        FROM node_tags 
        WHERE tag_id = (SELECT MAX(id) FORM tags WHERE name = 'dog')
        

        在您尝试类似的操作之前进行备份;)

        【讨论】:

        • 由于同时尝试读写node_tags而失败。
        • 我相信SGDB会做所有​​的选择,然后再做插入,但是在这种情况下,他可以把选择结果放在一个php数组中,然后再做一段时间插入到一个表中。
        • 查看 Gordon Linoff 的回答中的 cmets,我进行了测试,但错过了与临时表有关的一个重要因素。
        • @Kolink 你的答案更好。为获得最佳性能,您可以仅使用 'dog' node_tags 将值插入临时表中,并使用干净的表插入,以避免不必要的 i/o。
        【解决方案4】:

        您不能在一个查询中执行此操作,因为您需要插入依赖于从同一个表中选择数据的数据。假设您在(node_id,tag_id) 上定义了一个唯一键,您可以获得的最接近的是这样的:

        CREATE TEMPORARY TABLE `tmp` (`node_id` TEXT, `tag_id` TEXT); # Choose better column types if possible
        INSERT INTO `tmp` SELECT `node_id`, `tag_id` FROM `node_tags`;
        SET @id_cat = (SELECT `id` FROM `tags` WHERE `name`='cat'),
            @id_dog = (SELECT `id` FROM `tags` WHERE `name`='dog');
        INSERT IGNORE INTO `node_tags` (`node_id`, `tag_id`)
          SELECT `node_id`, @id_cat FROM `tmp` WHERE `tag_id`=@id_dog
          UNION
          SELECT `node_id`, @id_dog FROM `tmp` WHERE `tag_id`=@id_cat;
        DROP TABLE `tmp`;
        

        您可以将其粘贴到您的 MySQL 管理器工具中,它应该可以工作。

        【讨论】:

          【解决方案5】:

          以下查询获取所有没有猫 ID 的“狗”。然后将它们插入到表中:

          insert into node_tags(node_id, tag_id)
              SELECT id, $cat['id']
              FROM tags t join
                   node_tags nt
                   on t.node_id = nt.node_id
              WHERE t.name = 'dog'
              group by id
              having max(case when tag_id = $cat['id'] then 1 else 0 end) = 0
          

          【讨论】:

          • 我很确定这行不通,因为您正试图同时读取和写入 node_tags
          • @Kolink 。 . .这不是我所经历的限制。你有它的文件吗?应该运行的方式是“选择”首先运行,然后插入行。事实上,Mysql 5.5 文档明确表示这是可能的 (dev.mysql.com/doc/refman/5.5/en/insert-select.html)。
          • 我刚刚尝试了一个简单的insert into x (y) select y+10 from x 并收到“无法重新打开 x”错误消息。 - 编辑没关系,我的x 是一个临时表,这是不允许的。
          • @Kolink 。 . .文档确实说这是特定于版本的。我认为这取决于您使用的 mysql 版本。
          猜你喜欢
          • 2011-12-11
          • 1970-01-01
          • 1970-01-01
          • 2018-04-14
          • 2023-03-21
          • 2012-06-06
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多