• 締切済み

レコードなしは挿入、レコードありは更新する方法

該当レコードなしのときは挿入、該当レコードがあるときは更新する方法を教えてください データベース初心者です 該当レコードなしのときは挿入(INSERT)、該当レコードがあるときは更新(UPDATE)する方法を教えてください。 MySQL 5.0.67 レコードは下記のようになります。 desc table; +----------+----------------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +----------+----------------------+------+-----+---------+-------+ | val1 | smallint(6) | NO | PRI | 0 | | | val2 | smallint(6) | NO | PRI | 0 | | | val3 | smallint(6) | NO | PRI | 0 | | | date_y | char(4) | NO | PRI | | | | date_m | char(2) | NO | PRI | | | | pre | bigint(19) | NO | | 0 | | | now | bigint(19) | NO | | 0 | | +----------+----------------------+------+-----+---------+-------+ 下記のSQL文で更新を行いました。 UPDATE table as c, ( SELECT val1, val2, val3, now FROM table WHERE date_y='2010' and date_m='10' ) as n SET c.pre=n.now, c.now=n.now WHERE c.val1=n.val1 and c.val2=n.val2 and c.val3=n.val3 and c.date_y='2010' and c.date_m='11'; このSQL文をINSERT~ON DUPLICATE KEY UPDATEにした場合、どのようなSQL文になるのかをご教授頂ければ幸いです。 一応、下記URLを参照したのだけど、うまくSQL文が書けませんでした。 12.2.4.3. INSERT ... ON DUPLICATE KEY UPDATE 構文 http://dev.mysql.com/doc/refman/5.1/ja/insert-on-duplicate.html 以上、宜しくお願い致します。

  • MySQL
  • 回答数5
  • ありがとう数9

みんなの回答

  • nora1962
  • ベストアンサー率60% (431/717)
回答No.5

更新部分の > pre=values(now),now=values(now+day01+day02+day03~途中省略~+day29+day30+day31) を pre=values(now),now=values(now)+values(day01)+values(day02)+values(day03)~途中省略~+values(day31) に変えるとどうなりますか。

teams_black
質問者

お礼

nora1962さん お忙しいとは思いますが、 私のような初心者に丁寧に何度もご回答頂き本当にありがとうございます。 大変、感謝しております。

teams_black
質問者

補足

nora1962さん 何度も教えて頂き、本当にありがとうございます。 ただ、残念ながら、やはりうまくいきませんでした。 こちらで確認した内容をご報告させて頂きます。 ◆その1 INSERT INTO `table` ( val1, val2, val3, date_y, date_m, now, pre ) SELECT val1, val2, val3, date_y, '11', now, pre FROM `table` WHERE date_y='2010' and date_m='10' ON DUPLICATE KEY UPDATE pre=values(now),now=values(now)+values(day01)+values(day02)+values(day03)~途中省略~+values(day29)+values(day30)+values(day31); 文法上はこれで問題ないようです。教えて頂きありがとうございます。 ただ、nowに設定された値がnowでした。 期待していたのはnow+day01+day02~なのですが。。。 ◆その2 INSERT INTO `table` ( val1, val2, val3, date_y, date_m, now, pre ) SELECT val1, val2, val3, date_y, '11', now, pre FROM `table` WHERE date_y='2010' and date_m='10' ON DUPLICATE KEY UPDATE pre=values(now),now=values(day01); だと、nowに0が設定されます。 もちろん、dayに値が設定されていることは確認しております。 ◆その3 INSERT INTO `table` ( val1, val2, val3, date_y, date_m, now, pre ) ( SELECT val1, val2, val3, date_y, '11', now, pre FROM `table` WHERE date_y='2010' and date_m='10' ) as n ON DUPLICATE KEY UPDATE pre=values(now),now=values(now)+values(n.day01)+~途中省略~; as句を使用しようと試みましたが。。。 これだと、文法エラーになります。 エラー内容は You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'as n ON DUPLICATE KEY UPDATE pre=values(now),now=values(n.day01' at line 6 当然、こちらでも調査させて頂きますが、また何か方法がありましたら、教えて頂ければ嬉しいです。

  • nora1962
  • ベストアンサー率60% (431/717)
回答No.4

一応 INSERT INTO `table` ( val1, val2, val3, date_y, date_m, now, pre ) SELECT val1, val2, val3, date_y, '11', now, pre FROM `table` WHERE date_y='2010' and date_m='10' ON DUPLICATE KEY UPDATE pre=values(now),now=values(now); でどうでしょう。 ただ、このSQLでは年の繰り上がりなどの場合の処理が面倒ですね。 後、一月1レコードという設計も正規化という観点から言えばかなり問題があるように思えます。

teams_black
質問者

お礼

# 更に追記させて頂きます ちなみに以下のSQL文だと文法エラーとなります。 INSERT INTO `table` ( val1, val2, val3, date_y, date_m, now, pre ) SELECT val1, val2, val3, date_y, '11', now, pre FROM `table` WHERE date_y='2010' and date_m='10' ON DUPLICATE KEY UPDATE pre=values(now),now=values(now+day01+day02+day03~途中省略~+day29+day30+day31);

teams_black
質問者

補足

nora1962さん 何度もお世話になり、恐縮致します。 また、SQL文を教えて頂き誠にありがとうございます。 > ただ、このSQLでは年の繰り上がりなどの場合の処理が面倒ですね。 その辺はプログラム上でカバーします。こんな感じで。。。 pre_year = now_year; pre_month = now_month - 1; if(pre_month == 0){ // 該当月が1月なら pre_y--; // 該当年を-1年 pre_m = 12; // 該当月を12月 } ※C/C++言語です > 後、一月1レコードという設計も正規化という観点から言えばかなり問題があるように思えます。 ごめんなさい。既存のデータベースを使用しているため、変更ができないんです。。。 また、運用上、本テーブルは1日に1~2回程度しか更新されないので、さほど効率は重視されていないようです。 ただ、新規に開発を行う際はご参考にさせて頂きます。 で、nora1962さんの記載したSQL文を確認させて頂きました。 ただ、やはりこちらでも、私の端折った質問が悪かったですね。 下記URLと同じく、実際のテーブルは以下のようになります。 http://oshiete.goo.ne.jp/qa/6353578.html pre:前月のval1,val2,val3が同じnowの値が保存されます。 now:本月のpre+day01~day31までの合計値が保存されます。 desc table; +----------+----------------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +----------+----------------------+------+-----+---------+-------+ | val1 | smallint(6) | NO | PRI | 0 | | | val2 | smallint(6) | NO | PRI | 0 | | | val3 | smallint(6) | NO | PRI | 0 | | | date_y | char(4) | NO | PRI | | | | date_m | char(2) | NO | PRI | | | | pre | bigint(19) | NO | | 0 | | | now | bigint(19) | NO | | 0 | | | day01 | smallint(6) unsigned | NO | | 0 | | | day02 | smallint(6) unsigned | NO | | 0 | | ~~~ 途中省略 ~~~ | day30 | smallint(6) unsigned | NO | | 0 | | | day31 | smallint(6) unsigned | NO | | 0 | | +----------+----------------------+------+-----+---------+-------+ nora1962さんの記載されたSQL文ですと、nowがpreと同じ値になります。 nowには本月(本レコード)のpre+day01~day31までの合計値を設定(更新)したいと思っております。 以上、何度もご質問をして申し訳ありませんが、宜しくお願い致します。

  • yambejp
  • ベストアンサー率51% (3827/7415)
回答No.3

>ON DUPLICATE KEY UPDATE ご提示のURLにきちんと例文も書かれているみたいですけどね・・・ ようはプライマリかユニークのカラムをキーにして競合するとき UPDATEするわけです。 参考までにこんな感じです。 create table tbl(id int not null,data1 varchar(10),data2 varchar(10),primary key(id)); insert into tbl value(1,'aaa','bbb') on duplicate key update data1='aaa',data2='bbb'; insert into tbl value(2,'ccc','ddd') on duplicate key update data1='ccc',data2='ddd'; insert into tbl value(3,'eee','fff') on duplicate key update data1='eee',data2='fff'; insert into tbl value(2,'xxx','yyy') on duplicate key update data1='xxx',data2='yyy'; そもそもUPDATEとINSERTは性質が違うものなので、別々に処理する方がいいと 思うんですけどね

teams_black
質問者

お礼

yambejpさん ご回答頂きまして、ありがとうございます。

teams_black
質問者

補足

yambejpさん ご回答頂きまして、誠にありがとうございます。 ただ、こちらの質問の書き方が悪かったようで、申し訳ありません。 私が知りたいのは下記SQL文をどうやって「INSERT~ON DUPLICATE KEY UPDATE」を使用したSQL文になるのかが知りたいです。 ※サンプルを参考にいろいろ記述を変えたけど、私が未熟なばかり、文法エラーが出るんです。。。 UPDATE table as c, ( SELECT val1, val2, val3, now FROM table WHERE date_y='2010' and date_m='10' ) as n SET c.pre=n.now, c.now=n.now WHERE c.val1=n.val1 and c.val2=n.val2 and c.val3=n.val3 and c.date_y='2010' and c.date_m='11'; コレだと文法エラーになる。。。 ↓ INSERT INTO table as c, ( SELECT val1, val2, val3, now FROM table WHERE date_y='2010' and date_m='10' ) as n VALUE (n.kukan_cd, n.updown, n.honsen, n.nowtupan) ON DUPLICATE KEY UPDATE c.pre=n.now, c.now=n.now WHERE c.val1=n.val1 and c.val2=n.val2 and c.val3=n.val3 and c.date_y='2010' and c.date_m='11'; エラーメッセージ: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'as c,(SELECT val1, val2, val3, now FROM t' at line 1 > そもそもUPDATEとINSERTは性質が違うものなので、別々に処理する方がいいと思うんですけどね ごめんなさい。。。次回、コードを作成する際はご参考にさせて頂きます。

  • yambejp
  • ベストアンサー率51% (3827/7415)
回答No.2

ロジック的には以下のどれか (1)REPLACEを使う (2)プライマリをつかって削除して、その後新規INSERTで投入をする。 (3)プライマリをつかってIGNOREでINSERTして、その後UPDATEで更新をかける。 実は(1)と(2)はロジック的には同じ感じです 文書的には(1)が簡単ですが、SQLの処理としては(3)が効率がいいです。

teams_black
質問者

お礼

yambejpさん ご回答頂きまして、ありがとうございます。

  • askaaska
  • ベストアンサー率35% (1455/4149)
回答No.1

REPLACE文を使ってはどお?

teams_black
質問者

お礼

askaaskaさん ご回答頂きまして、ありがとうございます。

teams_black
質問者

補足

ご回答ありがとうございます。 > (1)REPLACEを使う > (2)プライマリをつかって削除して、その後新規INSERTで投入をする。 > (3)プライマリをつかってIGNOREでINSERTして、その後UPDATEで更新をかける。 についてですが、(1)、(2)はできれば、使用したくないですね。 実際のレコードは、他にも多数のカラムが存在していて、削除すると、再度レコードの作り直しになりますので。 それと(3)についてですが、調べさせて頂きました。 http://dev.mysql.com/doc/refman/4.1/ja/insert.html 該当のレコードが無い場合は挿入で、該当のレコードがある場合は、無視され、挿入されないとなっておりました。 これも、挿入されない場合、UPDATEを呼び出さなければならず、ちょっと手間が掛かるので控えたいのです。 やはり1文で済ませたいので「ON DUPLICATE KEY UPDATE」を使用したいです。 ただ、マニュアルを読んでもコードの書き方が分からず、文法エラーとなってしまうので、 大変申し訳ありませんが、教えて頂けるとありがたいです。

関連するQ&A

  • 該当レコードなしでエラーを発生させない方法

    レコードなし、もしくは該当レコードなしでエラーを発生させない方法を教えてください データベース初心者です レコードなしもしくは該当レコードなしの状態で検索を行うとエラーが発生します。 エラーを発生させずに検索を行う方法があれば教えてください。 MySQL 5.0.67 レコードは下記のようになります。 desc table; +----------+----------------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +----------+----------------------+------+-----+---------+-------+ | val1 | smallint(6) | NO | PRI | 0 | | | val2 | smallint(6) | NO | PRI | 0 | | | val3 | smallint(6) | NO | PRI | 0 | | | date_y | char(4) | NO | PRI | | | | date_m | char(2) | NO | PRI | | | | pre | bigint(19) | NO | | 0 | | | now | bigint(19) | NO | | 0 | | +----------+----------------------+------+-----+---------+-------+ 下記のSQL文で検索を行いました。 SELECT t.date_y, t.date_m FROM table t, ( SELECT date_y,max(date_m*1) as date_m FROM table WHERE date_y= ( SELECT max(date_y*1) as date_y FROM table WHERE (now - pre) > 0 ) ) s WHERE t.date_y=s.date_y and t.date_m=s.date_m; レコードなし、もしくは該当レコードがないとWHERE文のdata_yにnullが代入され、 本SQL文でエラーが発生します。 いろいろ調べて「EXISTS」「NOT EXISTS」「NULLIF」を利用するのかな? と思ったのだけど、下記URLを参照しても、うまくSQL文が書けませんでしたので、ご教授頂ければ幸いです。 6.4.2.6. EXISTS と NOT EXISTS http://dev.mysql.com/doc/refman/4.1/ja/exists-and-not-exists-subque... 6.3.1.4. フロー制御関数 http://dev.mysql.com/doc/refman/4.1/ja/control-flow-functions.html

    • ベストアンサー
    • MySQL
  • MySQLでTIMESTAMP型の列から現在日付の1週間以内のデータ検索をSQL文で

    タイトルの通りですが、MySQLのSELECT文についてです。 以下のようなテーブルがあったとします。 MEMBER{ ID SMALLINT M_DATE TIMESTAMP} このテーブルのM_DATEが現在の日付から一週間以内であるレコードの検索を以下のようなSQL文で実行しました。 SELECT * FROM MEMBER WHERE M_DATE BETWEEN (NOW() - 00000000070000) AND NOW(); 最初はこれでOKだと思っていたのですが、月をまたいだりした時に抽出されるべきではないレコードが表示されるので間違いに気付いたのですが、どう修正すべきなのか分からない状況です。 どなたか良い方法があれば、教えて頂きたいです。 よろしくお願いします。

    • ベストアンサー
    • MySQL
  • Accessで最新レコード20件を表示させるには

    Access2000のクエリで、最新のレコード20件を表示させたい場合どのようにしたら良いでしょうか? レコード番号があり、最新番号が100の場合、80~100を表示させたいのですが。 SQLベースだと SELECT no_c FROM table ORDER no_c DESC limit 20 など、limitが使えますが、Accessでこれに該当するものはありますか?

  • date型でのbetweenについて教えてください。

    皆様、新年明けましておめでとうございます。 早速ですが、date型でのbetweenについて教えてください。 SQL文 SELECT * FROM test WHERE date between date '2007-12-01' and date '2007-12-31' を発行すると、2007-12-31のレコードがあるのに該当しません・・・ 試しにSQL文を SELECT * FROM test WHERE date between date '2007-12-01 00:00:00' and date '2007-12-31 23:59:59' としても2007-12-31のレコードは検索されません・・・ SQL文を SELECT * FROM test WHERE date between date '2007-12-01' and date '2008-01-01' にすると2007-12-31が該当するのですが、 SELECT * FROM test WHERE date between date '2007-12-01' and date '2007-12-31' では2007-12-31のレコードは該当しないものでしょうか?? select * from test where num between 10 and 100 とした場合では、num が 10 ~ 100 のものが問い合わされますよね?? date型になるとこうならないのでしょうか?? よろしくお願いします。

  • あるIDごとの最高値のレコード抽出について

    下記のようなテーブルがあるとします。 それぞれの人の最高得点であるレコードを抽出したいのですが可能でしょうか。 テーブル:result no id point date -------------------- 1 A 60 ... 2 A 70 3 B 50 4 B 90 期待出力 no id point date ------------------- 2 A 70 ... 4 B 90 自分でも色々考えたつもりですが、例えば select max(point) from result group by id; とすると 70,90 という値は抽出されますが、該当レコードの全カラムを出力させたいです。 もし同じidで同じpointのレコードがあった場合は、dateの新しいほうを優先したいです。 id,point,dateがまったく同じレコードは存在しないと仮定します。 この他にもdistinct等も考えましたが、指定したカラムが重複した場合どのレコードが選択されるかは 不定のようですので使えそうにありません。 そもそもSQLだけでこのような出力が可能かどうかもわかりません…。 テーブルの設計が悪いというのもあるのでしょうか。 どなたかご助言くだされば幸いです。

  • 複数レコードのデータを1レコードに集約したい

    お世話になります。 複数レコードのデータを1レコードに集約したいのですが色々試してみましたが上手くいきません。 まず、以下のようなテーブルがあります。 TableA(キーはID) ID NO 1, 2 TableB(キーはIDとNO) ID NO SYU_NO FUKU_NO 1, 1, 1, 1 1, 2, 1, 2 1, 3, 2, 1 2, 1, 1, null    ・    ・ TableC(キーはIDとKUBUNとNO) ID KUBUN(SYU or FUKU) NO START END KAKUNIN 1, 1, 1, 20090101, 20091231, 20090310 1, 1, 2, 20090201, 20091130, 20090310 1, 2, 1, 20090401, 20100331, 20090312    ・    ・ これを、以下のようなレコードにしたいのですが・・。 ID START(SYU_NO) END(FUKU_NO) START(FUKU_NO) END(FUKU_NO) 1, 20090101, 20091231, 20090401, 20100331 以下のようなselect文を作成しましたが・・。 select A.ID || ',' || case when C.KUBUN = 1 then C.START end || ',' || case when C.KUBUN = 1 then C.END end || ',' || case when (C.KUBUN = 2 and B.FUKU_NO = C.NO) then C.START end || ',' || case when (C.KUBUN = 2 and B.FUKU_NO = C.NO) then C.END end || ',' || from TableA A inner join TableB B on A.ID = B.ID and A.NO = B.NO inner join TableC C on B.ID = C.ID and ((C.KUBUN = 1 and B.SYU_NO = C.NO) or (C.KUBUN = 2 and B.FUKU_NO = C.NO)) ; 以下のような結果が返ってきます。 ID START(SYU_NO) END(FUKU_NO) START(FUKU_NO) END(FUKU_NO) 1, 20090101, 20091231, , 1, , , 20090401, 20100331 実は別サイトでも投稿しておりますが回答がなく大変困っております。 どうか宜しくお願い致します。

  • データ抽出の速度について

    オラクルのあるテーブルに10万件のレコードがあります。カラム数は30です。 初歩的な話になりますが、(1)と(2)はどちらが速いでしようか。 (1) SELECT x FROM TBL_A WHERE ...AND...AND...AND...AND...AND という複雑なSQLを実行するとします。 これに該当するレコード数は[3千件]です。 これで、 value =RS("x") RS.movenext を3千回実行する。(sqlを実行するのは一回のみ) (2) 同じく複雑なSQLを実行します。 SELECT x FROM TBL_A WHERE ...AND...AND...AND...AND...AND VAL=15 これに該当するレコード数は[1]件です。 value =RS("x") で取得。 また同じSQLを3千回実行する。 上記について初歩的ですが、確認したいです。 sql実行の対象レコードが、数万に上っても、SQLを何回も実行したほうがやはり遅いでしょうか。 また、上記の3千が、100件程度とか少ない場合、速度差が逆転しないでしょぅか。

  • レコードのコピー

    既存のレコードを1項目だけ変更して同一テーブルに登録します。 こちらで以前質問されていた内容を参考に以下のSQLを作ってみましたが、「SQLコマンドが正しく終了されていません」といわれてしまいます。 どうすればうまくいくのかわかりません。 教えてください。よろしくお願いします。 (ちなみに以下のSQLでの「NO」は変更項目です) INSERT INTO table (column1, column2, column3, KOUSIN_DATE) SELECT A.column1, A.column2, NO, TO_DATE(2005/12/01,'YYYY/MM/DD HH24:MI:SS') FROM table AS A WHERE A.column1 = '9999';

  • 「Duplicate entry '1' for key 'PRIMARY'」というエラー。

    mysql> show fields from do; +-----------+------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-----------+------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | parent_id | int(11) | YES | | 0 | | | data_time | bigint(20) | YES | | NULL | | | text | text | YES | | NULL | | +-----------+------------+------+-----+---------+----------------+ というテーブルに、 insert into do values (1,1,1,'kkk'); などと、SQL文を実行すると、 Duplicate entry '1' for key 'PRIMARY' というエラーが出ます。 これはどういう意味のエラーなのでしょうか?

    • ベストアンサー
    • MySQL
  • MySQL+PHP 特定レコードの更新と作成

    MySQL+PHPの初心者です。 特定レコードの変更または新規作成のサンプルなどあればお教えいただけるでしょうか。 例えば特定商品の単価のレコードがあれば新しい単価に変更と そのレコードが無ければ新規にレコードを作成するようなケースになります。 VBAなどでは検索のSQL文からレコードセットを作成し レコードが無い場合は レコードセット名.addnewで必要なフィールドに 値をセットし レコードセット名.update 該当するレコードがあった場合は レコードセット名.edit で必要なフィールドに 値をセットし レコードセット名.updateなど簡単な処理なのですが MySQL+PHP の場合データの検索と新規レコードの単純な記述は ある程度はわかるのですが上記のようなケースは実際どのように 書かれているのかお教え願えると幸いです。 商品単価テーブルには商品コードと単価のフィールドになります。 よろしくお願いいたします。

    • ベストアンサー
    • MySQL