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."'");

    }

}

ご覧のとおり、反復内でクエリを実行しているため、私のコードは非常に悪く効率的ではありません。これを行うより良い方法を知っていますか?できれば、たった 1 つの 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ため、テーブル内での重複は許可されません。

2 番目は、重複によって生成されたエラーを無視して、新しいレコードを挿入します。

3 番目は古いレコードを削除します。

正直なところ、stepの代わりにignoreon キーワードを使用してこれを行うこともできます。ただし、これは非常に一般的であるため、理論的には別のエラーが誤って無視される可能性があります。許可されているものについては、より具体的です。updateinsertignoreon 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_ids と古いタグ以外のすべてのタグの間で完全なクロス積を作成します。次に、既存の との左結合を行いimages_tags、チェックを使用してnull、既に存在するすべてのペアを除外します。これにより、データベース内のいずれにも一致しないimage_idとのペアのリストが生成されます。tag_id最後にグループ化するimage_idので、画像ごとに新しい行を 1 つ追加するだけです。

これを行った後、 で行を削除できますtag_id = $oldtag

SQLFIDDLE

images_tagsこれに関する唯一の問題は、行の ID が変更されることです。クエリを使用してすべてをワンステップで実行する方法があるかもしれUPDATEませんが、その問題はありませんが、クエリをそのようにする方法がわかりません。

于 2013-07-24T21:34:51.890 に答える