我在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查询中。感谢。
答案 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_id
和tag_id
对的列表,这些对与数据库中的任何内容都不匹配。最后,我们按image_id
分组,因此我们只为每个图片添加一个新行。
执行此操作后,您可以使用tag_id = $oldtag
删除行。
唯一的问题是它会更改images_tags
行的ID。可能有一种方法可以使用UPDATE
查询一步完成所有这一切,这不会有问题,但我不确定如何将查询转换为该问题。