MySQL查询在图片中重新分配标签并避免重复

时间:2013-07-24 20:40:12

标签: php mysql sql

我在MySQL中有以下结构,表'images_tags':

id | image_id | tag_id
----------------------
1  |  243     | 52
2  |  94      | 52
3  |  56      | 52
4  |  56      | 53
5  |  56      | 54

表'标签':

id  | tag     
---------------
52  |  fashion 
53  |  cars  
54  |  sports  
55  |  bikes  

我正在我的CMS中构建一个删除标签的功能,因为我需要将包含该标签的所有图片重新分配给另一个标签。问题是图片已经分配了新标签,我想避免可能的重复记录。

我无法在SQL中找到正确的方法,因此我尝试使用PHP,如下所示:

$result=mysql_query("select image_id from images_tags where tag_id='".$oldtag."'");
while($row=mysql_fetch_assoc($result)){

    $result2=mysql_query("select id from images_tags
    where image_id='".$row['image_id']."' and tag_id='".$newtag."'");

    if(mysql_num_rows($result2)==0){

        mysql_query("update images_tags set tag_id='".$newtag."'
        where image_id='".$row['image_id']."' and tag_id='".$newtag."'");

    }

}

正如您所看到的,我的代码非常糟糕且无效,因为我在迭代中运行查询。你知道更好的方法吗?最好只在一个SQL查询中。感谢。

2 个答案:

答案 0 :(得分:1)

当我想到这个问题时,我更容易想到“插入新的图像标签,如果合适,然后删除旧的标签”。

以下代码采用这种方法:

create unique index image_tags_unique on image_tags(image_id, tag_id);

insert into image_tags
    select image_id, <newtagid>
    from image_tags
    where tag_id = <oldtagid>
    on duplicate key ignore;

delete from image_tags
    where tag_id = <oldtagid>;

第一步在image_tags上创建一个唯一索引,因此表中不允许重复索引。

第二个插入新记录,忽略重复生成的任何错误。

第三个删除旧记录。

说实话,您也可以使用ignore上的update关键字代替insert步骤执行此操作。但是,ignore非常通用,因此 - 理论上 - 可能会错误地忽略另一个错误。 on duplicate key ignore对于允许的内容更为具体。

答案 1 :(得分:0)

我认为这会向images_tags添加符合条件的新行。

insert into images_tags (image_id, tag_id)
select image_id, tag_id
from (select i.image_id image_id, t.id tag_id
      from images_tags i
      join tags t
      where i.tag_id = $oldtag and t.id != $oldtag) crossp
left join images_tags existing
using (image_id, tag_id)
where existing.id is null
group by image_id

crossp子查询在当前具有旧标记的所有image_id与旧标记以外的所有标记之间创建完整的交叉产品。然后我们使用现有images_tags进行左连接,并使用null检查过滤掉已存在的所有对。这会生成一个image_idtag_id对的列表,这些对与数据库中的任何内容都不匹配。最后,我们按image_id分组,因此我们只为每个图片添加一个新行。

执行此操作后,您可以使用tag_id = $oldtag删除行。

SQLFIDDLE

唯一的问题是它会更改images_tags行的ID。可能有一种方法可以使用UPDATE查询一步完成所有这一切,这不会有问题,但我不确定如何将查询转换为该问题。