人力検索はてな
モバイル版を表示しています。PC版はこちら
i-mobile

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

●質問者: disca
●カテゴリ:ウェブ制作
✍キーワード:PHP SQL データ プログラム 入力
○ 状態 :終了
└ 回答数 : 3/3件

▽最新の回答へ

1 ● tadashi0805
●27ポイント

一番手抜きな方法です。

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

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

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

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

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

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

◎質問者からの返答

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

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

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


2 ● tadashi0805
●27ポイント

いえ、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()関数を順に呼ぶことで、やはり条件分岐は不要で、同じ処理は可能です。

◎質問者からの返答

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

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

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

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


3 ● canadie
●58ポイント

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での条件分岐が必要になってしまうので質問の条件は満たせませんが参考までに。

関連質問


●質問をもっと探す●



0.人力検索はてなトップ
8.このページを友達に紹介
9.このページの先頭へ
対応機種一覧
お問い合わせ
ヘルプ/お知らせ
ログイン
無料ユーザー登録
はてなトップ