質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.69%

php ON DUPLICATE KEY UPDATEについて

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 1,272

earnest_gay

score 403

user_idがuniqueKeyです。

            $sql  = "INSERT IGNORE INTO user_image";
            $sql .= " (user_id,file,type,name)";
            $sql .= " VALUES ('$id','$file','$file_type','$file_name')";
            $sql .= " ON DUPLICATE KEY UPDATE";
            $sql .= " file = '$file'";
            $sql .= " ,type = '$file_type'";
            $sql .= " ,name = '$file_name'";

            $stmt = $pdo->query($sql);

イメージ説明

user_id 70が画像更新ページなどで処理実行すると
user_id 70は存在するので更新されます。

ちょっとテーブル構造を変えてこんな感じにしようとします。
イメージ説明

しかし、user_idがuniqueKeyなのでid82以降のレコードは追加されることなく更新になってしまうので、

最終的にこうなってしまいます。
イメージ説明

更新対象として、user_idとnameかsizeがuniqueKeyなら、、、ということをしたいんですが、これは極端にsizeもuniqueKeyにするだけで勝手に判断してくれるのでしょうか?


追記

user_idとsizeをuniqueにして試してるのですが、下記のようになってしまいます。

イメージ説明

SQLの部分は下記です。

//取得サイズリスト作成
    for($px=25;$px<=500;$px+=25) {
        if($px <= 100) {
            //25px単位
            $size_list[] = $px;
        } else {
            //50px単位
            if($px % 2 == 0) {
                $size_list[] = $px;
            }
        }
    }

foreach ($size_list as $key => $value) {


            $sql  = "INSERT IGNORE INTO user_image";
            $sql .= " (user_id,file,type,name,size)";
            $sql .= " VALUES ('$id','$file','$file_type','$file_name','$prefix')";
            $sql .= " ON DUPLICATE KEY UPDATE";
            $sql .= " file = '$file'";
            $sql .= " ,type = '$file_type'";
            $sql .= " ,name = '$file_name'";
}

//で何回か回してます。
//肝心なのはSQLの部分、、、

イメージ説明

レコードがないときにはインサートされて
レコードがあるときにはUPDATEするには
本質問ではどうすればよいでしょうか?

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • turbgraphics200

    2017/01/26 18:44

    uniqueにする/したい理由はなんでしょうか。

    キャンセル

回答 2

checkベストアンサー

+5

複合一意制約の定義方法についてはyambejpさんが回答済ですので別の観点から回答をば。

今回のような一意制約を変更するという行為は、
業務要件に大きなインパクトを与えることを先ず抑えてください。

今回1人のユーザが複数ファイルを登録できるようにしたい、
という要件から一意制約キーの変更に思い至ったと思われますが、
この一意キーの付け方次第で実現できること、
できないことが大きく変わるので仕様について整理する必要があります。

以下に一意制約の定義パターンと、
その際に発生する暗黙的な仕様を浮き彫りにしていきます。

  • ユーザIDで一意
    → 1ユーザ1ファイルしか登録できない。
    (恐らく変更前の状態)

  • ユーザID、ファイル名で一意
    → 1ユーザ複数ファイルを登録できる。
    同名ファイルを登録した場合は上書きされる。

  • ユーザID、サイズで一意
    → 1ユーザ複数ファイルを登録できる。
    同一サイズのファイルを登録した場合は同一サイズのファイルが上書きされる。
    つまり名称が違う全然別ファイルでもサイズが被れば上書きされる。
    (恐らく質問者様の現状)

  • ユーザID、ファイル名、サイズで一意
    → 1ユーザ複数ファイルを登録できる。
    同名、同サイズのファイルを登録した場合のみ上書きされる。
    つまりサイズ違いは名前が一緒のファイルでも別物扱いとなる。

  • ユーザIDで一意、かつファイル名で一意(おまけ)
    → 1ユーザ1ファイルしか登録できない。
    かつ他のユーザで同名ファイルの登録があるとそのファイルが上書きされる。
    (複合一意キーの認識誤りの場合に陥ることがあるミス)


一意制約の付け方次第で、
ここまで暗黙的な仕様が変化するので、
実現したいこと・満たすべき要件をきちんと整理してから作業を行うようにしましょう。

追記

質問者様のキャプチャ画像今頃目を通してみましたが、
もしかしてユーザIDとサイズそれぞれで一意制約を定義してませんか?

その場合は以前に回答したパターンの内、
4つ目で紹介したような振る舞いとなります。

つまるところ、

  • 1ユーザは1ファイルしか登録できない(同ユーザの2回目以降の登録は常に上書き)
  • 同サイズのファイルは全ユーザ分を含めて1つしか存在できない(サイズが同じファイルがあれば常に上書き)

となってしまいますよ。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+4

user_idとnameかsizeがuniqueKey

であれば複合unique属性で「user_id,name,size」で
設定してみてはどうでしょうか?

sample

うまく動かないと言うのでsampleつけときます

create table tbl(id int not null primary key auto_increment
,uid int,name varchar(20),size int,hoge varchar(20)
,unique key(uid,name,size));


順次データ投入

insert into tbl(uid,name,size,hoge) values(1,'aaa',100,@a:='hoge1') 
on duplicate key update hoge=@a;
insert into tbl(uid,name,size,hoge) values(1,'aaa',200,@a:='hoge2') 
on duplicate key update hoge=@a;/*uidとnameが一緒だけどsizeが違うのでOK*/
insert into tbl(uid,name,size,hoge) values(1,'bbb',100,@a:='hoge3') 
on duplicate key update hoge=@a;/*uidとsizeが一緒だけどnameが違うのでOK*/
insert into tbl(uid,name,size,hoge) values(1,'aaa',100,@a:='hoge4') 
on duplicate key update hoge=@a;/*uidとsizeとnameが一緒なのでhogeを更新*/
insert into tbl(uid,name,size,hoge) values(2,'aaa',100,@a:='hoge5') 
on duplicate key update hoge=@a;/*sizeとnameが一緒だけどuidが違うのでOK*/

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/01/26 21:53

    横槍ですが、
    要件的にはユーザIDとファイル名で一意なのが適切な気がしてならないですね。

    同じユーザが同じファイル名でファイルを登録してるのに、サイズ違いが出ると別物として扱うのはレア過ぎる気がします・・・

    キャンセル

  • 2017/01/26 21:57

    連投で申し訳ないですが・・・

    履歴的にバージョン管理がしたいにしても、サイズ変化だけは履歴管理するとなって微妙ですし^^;

    キャンセル

  • 2017/01/26 22:27

    Panzer_vorさん

    確かに言われてみればファイル名が一緒なのに上書きしないというのは
    あまり理にかなわないですね
    なんとなく仕様のとおりコードを書いてしまいましたが
    仕様を見直すことも時には必要ですね

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.69%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる