SQL Postgres の質問(Insert Update)です。

データを入力する上で、データが無ければInsertする。データがあればUpdateする方法をプログラム(PHP)で記述しない方法で、ご教授ください。おねがいします。

回答の条件
  • 1人2回まで
  • 登録:2006/03/23 17:16:05
  • 終了:2006/03/29 12:25:30

回答(3件)

id:tadashi0805 No.1

tadashi0805回答回数287ベストアンサー獲得回数292006/03/23 17:30:53

ポイント27pt

一番手抜きな方法です。

・データのありなしのキーが、テーブル上ユニークである

・クエリを毎回2回発行しても構わない

ってことなら、insertした後でupdateを行えば、

・データなしなら、insertが成功し、updateも成功する

・データありなら、insertが失敗し、updateが成功する

となって、結果的に質問で行いたいことが可能です。

id:disca

回答ありがとうございます。

つまり… Select してデータがあるかどうか確認する。データがあればUpdate、データが無ければInsertということでしょうか?PHPで、条件分岐を行うことは避けたいのでSQL一行で実装(PGSQL?)する方法を教えていただけますでしょうか?

ちなみに、PGSQLは無知で、PHP&PostgreSQLでできるのかどうかも教えていただけますと大変助かります。よろしくおねがいいたします。

2006/03/23 18:06:54
id:tadashi0805 No.2

tadashi0805回答回数287ベストアンサー獲得回数292006/03/23 18:49:57

ポイント27pt

いえ、selectで確認する必要は、前回答の

・データのありなしのキーが、テーブル上ユニークである

の条件に合致すれば、必要ありません。

ユニーク属性が付いていると、insert文は既に該当レコードが存在している場合は、insertを行いません。selectで確認するかどうかの話を気にされているのなら、恐らく条件は合致するのではないでしょうか。

そうすると、

データなし:insert実行→成功、update実行→成功

データあり:insert実行→失敗、update実行→成功

となって、結果的になければinsert、あればupdateと同じ結果になります。

複数クエリを投げるためには、下記URLに書いてある方法でOKです。単純にクエリ文字列を、;で連結するだけ、条件分岐も必要ありません。

http://php.oss.eznetsols.org/manual/ja/function.pg-query.php

ただ、PostgreSQLは、トランザクションで更新しますから、2つのクエリのどちらかが失敗(特にデータありでinsertが失敗するパターン)するとRollbackする可能性があります。ちょっと、今手元にPostgreSQLサーバーがないので確認できないのですが。

Rollbackしてしまうなら、単純に2回pg_query()関数を順に呼ぶことで、やはり条件分岐は不要で、同じ処理は可能です。

id:disca

回答ありがとうございます。

ユニーク属性が付いている場合のInsertですが、

PHPの場合、すでにデータがある場合、WARRNINGが出力されます。そのため、Selectで先にデータの有無を調べてからInsertしなければならないのか?と考えていました。こちらについては皆さまはどう対応されているのでしょうか?

あと複数クエリの送信についてですがありがとうございます、参考になりました。

2006/03/23 20:00:49
id:canadie No.3

canadie回答回数6ベストアンサー獲得回数12006/03/24 11:11:51

ポイント58pt

http://jp2.php.net/manual/ja/function.pg-query.php

確かにpg_query()で試してみるとWarningを吐きますね。マニュアルには記載がないですし、mysql_query()でも何も吐かないのですが……。

こういった場合、多少強引ですが、error_reporting()で一時的にWarningを抑制する方法があります。

なお、tadashi0805さんが指摘しているように、クエリを連結するとINSERTが失敗した場合にトランザクションが壊れたとみなされRollbackしてしまいます(UPDATEの結果が反映されません)ので2回pg_query()を呼ぶようにすればよいでしょう。つまり、


// INSERTの時だけWARINGの出力を抑制する

$lev=error_reporting(E_ALL ^ (E_WARNING | E_NOTICE));

// まずINSERT

pg_query('INSERT ....');

// エラー出力の条件を元に戻す

error_reporting ($lev);

// 次にUPDATE

pg_query('UPDATE ....');


で質問の条件を満たすことができます。

なお、BEGINなどで明示的にトランザクションを行っている場合もINSERTの失敗がトランザクションに影響を与えるので注意が必要です。これを防ぐにはSAVEPOINTとROLLBACK TOを使います。

参考: http://www.postgresql.jp/document/pg813doc/html/sql-update.h...

まずSAVEPOINTを設定し、直後にinsertを実行するようにします。

SAVEPOINT sp1;

insert実行;


このタイミングでinsertの失敗を検出し(pg_last_error()で取得できます)、失敗した場合のみ、

ROLLBACK TO sp1;

update実行

とすればトランザクションを壊さずにinsertかupdateのどちらかを実行することができます。この場合、PHPでの条件分岐が必要になってしまうので質問の条件は満たせませんが参考までに。

コメントはまだありません

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません