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

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

ただいまの
回答率

91.25%

  • MySQL

    4563questions

    MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

MySQLでON DUPLICATE KEY UPDATEをした際に元々入っていた値を使い回したい

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 675

k725

score 4

MySQLで下記のようなSQL文を実行した際に、思った結果とは違う結果になってしまいます。

INSERT INTO
    test(id, foo, bar, baz)
VALUES
    (1, 0, 0, 0)
ON DUPLICATE KEY UPDATE
    id = 1,
    foo = foo + 1,
    bar = foo + 1,
    baz = bar + 1;

なお、test テーブルには以下のようなデータが入っています。

id(A_I) foo bar baz
1 1 1 1

実行結果がこうなってしまいます。

id(A_I) foo bar baz
1 2 3 4

私が望んでた結果は以下のような感じなのですが、何か良い方法はありますか?

id(A_I) foo bar baz
1 2 2 2
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 3

checkベストアンサー

0

create table test(id int not null primary key auto_increment,foo int,bar int,baz int);
insert into test values(NULL,1,1,1);


だとして、

insert into test values(NULL, 0, 0, 0) on duplicate key update
id=1,foo = foo + 1,bar = foo + 1,baz = bar + 1;


してもduplicate keyはないので新しいデータが追加されるだけですよ

insert into test values(1, 0, 0, 0) on duplicate key update
baz = bar + 1,bar = foo + 1,foo = foo + 1;


のようidを明示してinsertして、逆からいれてあげるだけじゃないですか?

 追記

あまり推奨されていませんが変数経由で処理することも検討ください

insert into test values(1, 0, 0, 0) on duplicate key update
foo = (@a:=foo) + 1,bar = (@b:=bar)*0 + @a + 1,baz = @b + 1;

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2016/11/01 12:49

    申し訳ないです。values(NULL, 0, 0, 0)ではなく、values(1, 0, 0, 0)でした。

    キャンセル

  • 2016/11/01 12:53

    で、回答したとおりfoo→bar→bazをbaz→bar→fooのように
    逆からいれてやる件はいかがでしょうか?

    キャンセル

  • 2016/11/01 17:25

    変数経由の処理を追記しておきました

    キャンセル

0

foo = foo + 1,
    bar = foo + 1,
    baz = bar + 1;


ではなく

foo = foo + 1,
 bar = bar + 1,
 baz = baz + 1;

したらなりませんか?

idがPKでしょうか?
(NULL, 0, 0, 0)、1ではなくNULLですか?

追記

INSERT INTO
    test (id, foo, bar, baz)
VALUES
    (NULL, 0, 0, 0)
ON DUPLICATE KEY UPDATE
    id = 1,
    foo = foo + 1,
    bar = foo + 1,
    baz = bar + 1;


まずこれではvalueのidにNULLを指定しているのでai設定されているならどんどん(NULL, 0, 0, 0)でinsertされるだけでON DUPLICATE KEY UPDATEに入ってこないと思うのですが。。。。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2016/11/01 12:26

    実際のSQLクエリではもう少し複雑になっており、CASE文を使用しているので厳しいです。

    キャンセル

  • 2016/11/01 12:29

    それではやらいたい事が少し見えてこないのですが、foo,bar,bazをインクリメントしたいという事ではないのですか?

    キャンセル

  • 2016/11/01 12:29

    >idがPKでしょうか?
    >(NULL, 0, 0, 0)、1ではなくNULLですか?
    仰るとおりIDがプライマリキーになっています。(A_Iも有効にしているのでNULLで間違いないです)

    キャンセル

  • 2016/11/01 12:34

    >それではやらいたい事が少し見えてこないのですが、foo,bar,bazをインクリメントしたいという事ではないのですか?
    インクリメントしたいわけではありません。

    キャンセル

  • 2016/11/01 12:40

    失礼しました。確かにNULLではなく1ですね。 修正しました。

    キャンセル

0

これでは事足り無そうな感じですが。

insert into test (id) values(1)
  ON DUPLICATE KEY UPDATE 
  foo = foo + 1,
  bar = foo,
  baz = bar;

こんな感じを拡張されてはいかがでしょうか?

insert into test select * from test s where s.id=1
ON DUPLICATE KEY UPDATE
 foo = test.foo + 1,
 bar = s.foo,
 baz = s.baz;

s.fooで更新前の値が入るのを利用する。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2016/11/01 12:49 編集

    実際には1を加算するのでは無く、CASE文でfooなどを比較する…というのをfoo, bar, bazの=以降でやっています。

    ```
    (略)
    foo = (CASE WHEN foo > bar THEN :hoge ELSE foo END), # ここは思った通り
    bar = (CASE WHEN foo > bar THEN :fuga ELSE bar END), # fooが:hogeに変わった場合意図したとおりに動かない
    baz = (CASE WHEN foo > bar THEN :piyo ELSE baz END); #〃
    ```

    上記のような場合だと 条件自体が思っていたのと違ってしまうため困っています。

    キャンセル

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

ただいまの回答率

91.25%

関連した質問

同じタグがついた質問を見る

  • MySQL

    4563questions

    MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。