0

我在 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 查询中。谢谢。

4

2 回答 2

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关键字 onupdate而不是insertstep 来执行此操作。然而,ignore这是非常普遍的,所以——理论上——可能会有另一个错误被错误地忽略。这on duplicate key ignore对允许的内容更加具体。

于 2013-07-24T20:49:10.887 回答
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_id和对的列表。tag_id最后我们分组,image_id所以我们只为每个图像添加一个新行。

执行此操作后,您可以删除带有 的行tag_id = $oldtag

SQLFIDDLE

唯一的问题是它改变了images_tags行的 ID。可能有一种方法可以通过查询一步完成所有UPDATE操作,这不会有这个问题,但我不知道如何将我的查询变成那个问题。

于 2013-07-24T21:34:51.890 回答