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

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

新規登録して質問してみよう
ただいま回答率
85.48%
PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Q&A

解決済

4回答

2248閲覧

全ての入力フィールドにて内容が変わってもON DUPLICATE KEY UPDATEで新規追加させたくない

earnest_gay

総合スコア615

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

0グッド

0クリップ

投稿2016/07/11 02:49

編集2016/07/11 04:17

1つのページで登録と更新を作っているのですが、
下記コードの場合、projectTitleをUNIQUEにしているので
projectTitleを変えると変更ではなく追加になってしまいます。

この場合どうやって回避できるでしょうか?

$sql = "INSERT INTO user_vitae( user_id, projectTitle, projectsContents ) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE user_id = ?, projectTitle = ?, projectsContents = ? "; for($i=0;$i<count($_POST['projectTitle']);$i++) { $stmt = $this->pdo->prepare($sql); $stmt->execute([ $_SESSION['id'], $_POST['projectTitle'][$i], $_POST['projectsContents'][$i], $_SESSION['id'], $_POST['projectTitle'][$i], $_POST['projectsContents'][$i] ]); }

イメージ説明

案件名をUNIQUEにしているので、例えば
「test1」登録しておいて、
案件名を「test2」に変えたいなぁ~ってなったら、
更新ではなく新規登録になってしまいます。

これはどう防げばよいのでしょうか?

入力(変更)を必要としないカラムは
・id
・created
・user_id

この3つです。

イメージ説明


ソースはこうなっております。
全部載せると量が多いので必要なところだけを載せています。

<?php $dsn = 'mysql:dbname=test;host=localhost;charset=utf8'; $user = 'root'; $password = ''; $option = array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION); $pdo = new PDO($dsn, $user, $password, $option); $sql = "SELECT * FROM user_vitae WHERE user_id=? ORDER BY id ASC"; $stmt = $pdo->prepare($sql); $stmt->execute([$_SESSION['id']]); ?> <form action="" method="post"> <?php foreach ($stmt as $test) { ?> <table border=""> <tbody> <tr> <td>案件名</td> <td> <input type="text" name="projectTitle[]" maxlength="30" size="" placeholder="" value="<?php echo $test['projectTitle'] ?>"> </td> </tr> <tr> <td>案件内容</td> <td> <textarea name="projectsContents[]" rows="2" cols="21"> <?php echo $test['projectsContents'] ?> </textarea> </td> </tr> </tbody> </table> <br /> <br /> <?php } ?> <table id="vitae" class="vitae" border=""> <tbody> <tr> <td>案件名</td> <td> <input type="text" name="projectTitle[]" maxlength="30" size="" placeholder="" > </td> </tr> <tr> <td>案件内容</td> <td> <textarea name="projectsContents[]" rows="2" cols="21"> </textarea> </td> </tr> </tbody> </table> <div id="vitaeAdd"> <input type="button" value="業務経歴を追加する" onClick="vitaeAdd()"> <input type="button" value="業務経歴を削除する" onClick="vitaeDel()" id="vitae_btnDel" disabled="true"> </div> <br /> <input type="submit" name="submit" value="登録する"> </form>

↓登録&更新用の処理です。

$sql = "INSERT INTO user_vitae( user_id, projectTitle, projectsContents ) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE projectTitle = ?, projectsContents = ? "; for($i=0;$i<count($_POST['projectTitle']);$i++) { $stmt = $this->pdo->prepare($sql); $stmt->execute([ $_SESSION['id'], $_POST['projectTitle'][$i], $_POST['projectsContents'][$i], $_POST['projectTitle'][$i], $_POST['projectsContents'][$i] ]); }

↓現在の表示
イメージ説明

困っているところ

・ON DUPLICATE KEY UPDATEで案件名や案件内容をUNIQUEキーにしたら2つとも変更した場合、新規追加扱いになる

・ON DUPLICATE KEY UPDATEでuser_idをUNIQUEキーにしたら1件のレコードしか追加できなくなる

感じているところ

・案件名や案件内容をUNIQUEキーにしたら2つとも変更した場合、新規追加扱いになるのを防ぐために、idをUNIQUEにして、ON DUPLICATE KEY UPDATEに組み込んだらこの質問は解決されると思うが、そのSQLの組み方が分からない。

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

php

1$sql = "INSERT INTO user_vitae( 2 id, 3 user_id, 4 projectTitle, 5 projectsContents 6) VALUES (?, ?, ?, ?) 7 ON DUPLICATE KEY UPDATE 8 id = ? 9"; 10 11for($i=0;$i<count($_POST['projectTitle']);$i++) { 12 $stmt = $this->pdo->prepare($sql); 13 $stmt->execute([ 14 empty($_POST['id'][$i])?null:$_POST['id'][$i], // hiddenで持つ。※新規追加場合からなのでnullを渡す。 15 $_SESSION['id'], 16 $_POST['projectTitle'][$i], 17 $_POST['projectsContents'][$i], 18 $_POST['id'][$i] 19 ]); 20}

ですかね。rentoさんの設計の場合、タイトルと内容で一意とみなすのではなくIDで一意とみなすべきで、タイトルと内容はIndexとして利用すべきですね。

投稿2016/07/11 05:02

編集2016/07/11 05:05
mty.ad

総合スコア145

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

更新前、更新後のレコードを送信して処理をすればできると思います。
delete_flagなど論理削除用のフラグを用います。
・delete_flag=0 論理削除していない (boolean値でもOK)
・delete_flag=1 論理削除している

※提示されたレコードを例に記載します。
①更新前のレコードを一度論理削除する(delete_flag=1)
a)test1をdelete_flag=1で更新(UPDATE)

②追加したいレコードをdelete_flag=0でINSERTする
b)test2をdelete_flag=0で追加(INSERT)
c)(変更なければ)test1をdelete_flag=0で更新(UPDATE)

③delete_flag=1のレコードを削除する(DELETE)
d)b)の場合は、a)のレコードが削除されます。
e)c)の場合は、削除が空振りします。(DELETEは対象がなくてもステータスが正常になります)

上記①~③の処理を行えば、不要なレコードは消え、追加したレコードで置き換えできます。
③はループの外(COMMIT直前)で処理すればいいです。
(いちいち削除のクエリを①~②と一緒にする必要はないです、delete_flag=1でまとめて削除できます)

質問とは別ですが、データの一意性を保つため、トランザクション~コミットでくくったほうがいいですかね。

投稿2016/07/11 04:30

roast_chicken

総合スコア254

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

更新時には、IDも含めるようにしてください。

IDなしでON DUPLICATE KEY UPDATEとすると、2列にまたがってuniqueをかけているところで変更した場合に、そもそも重複しませんので、INSERTとして動いてしまいます。

投稿2016/07/11 04:26

maisumakun

総合スコア145184

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

earnest_gay

2016/07/11 04:38

回答ありがとうございます。 更新時には、IDも含めるとはどういうことでしょうか??? $sql = "INSERT INTO user_vitae( id, user_id, projectTitle, projectsContents ) VALUES (?, ?, ?, ?) ON DUPLICATE KEY UPDATE projectTitle = ?, projectsContents = ? "; for($i=0;$i<count($_POST['projectTitle']);$i++) { $stmt = $this->pdo->prepare($sql); $stmt->execute([ これから挿入するレコードのID??? $_SESSION['id'], $_POST['projectTitle'][$i], $_POST['projectsContents'][$i], $_POST['projectTitle'][$i], $_POST['projectsContents'][$i] ]); }
maisumakun

2016/07/11 04:43

MySQLのauto_incrementの場合、id列にNULLを入れておけば普通にINSERTできます。 もっとも、新規登録と更新を1本のSQLで済ませようということ自体、余計に面倒なことになっている気もしますが。
guest

0

ベストアンサー

ON DUPLICATE KEY UPDATE

user_id = ?,
projectTitle = ?,

とありますが、user_idをキーとするので
INSERTにだけ反映すれば良いのでは?

$sql = "INSERT INTO user_vitae( user_id, projectTitle, projectsContents ) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE projectTitle = ?, projectsContents = ? "; for($i=0;$i<count($_POST['projectTitle']);$i++) { $stmt = $this->pdo->prepare($sql); $stmt->execute([ $_SESSION['id'], $_POST['projectTitle'][$i], $_POST['projectsContents'][$i], $_POST['projectTitle'][$i], $_POST['projectsContents'][$i] ]); }

投稿2016/07/11 03:35

yambejp

総合スコア114839

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

earnest_gay

2016/07/11 03:48

回答ありがとうございます。 forでINSERTしていってるので、 このuser_vitaeテーブルはマルタテーブルではなくn構造(業務経歴)なので 複数のレコードが入る予定なのです... なので、主キーをuser_idにしてしまうとユーザーは1回しか登録できず、 以後、更新だけになってしまいます。 じゃあ毎回変わるprojectTitleカラムを主キーにすればいいんだと思っていたんですが、 projectTitleを変更したら、新規追加になってしまいます。 (該当がなくなってしまう為) そこで悩んでいるのです...
yambejp

2016/07/11 04:14

特定ユーザーIDにつきユニークなタイトルがつくのですね? であれば、 user_id,projectTitleの複合ユニーク属性をつけてください あるユーザーのタイトル違いは別文書になりますが 別ユーザーとタイトルが被っても大丈夫になります ホントはさらに管理上文書idカラムをつくってPRIMARYとしたほうがスマート
earnest_gay

2016/07/11 04:22

回答ありがとうございます。 特定ユーザーIDとはuser_idのことですよね? 他のユーザーと同じ案件名になることはないと思いますが、 もしかしたら、同じ案件名になるかもしれません。 問題点は下記ですが、複合ユニークを使うと本質問に追記させていただきました問題は解決されますでしょうか? ・ON DUPLICATE KEY UPDATEで案件名や案件内容をUNIQUEキーにしたら2つとも変更した場合、新規追加扱いになる ・ON DUPLICATE KEY UPDATEでuser_idをUNIQUEキーにしたら1件のレコードしか追加できなくなる
yambejp

2016/07/11 04:26

ちなみに、文書の修正をするなら、あたりまえですが 文書IDか元文書のタイトルが必要ですよ 修正元が特定できなければ修正のしようがないので
earnest_gay

2016/07/11 04:30

それは「誰の業務経歴か」を特定するために、下記で誰のものかを取得してvalueに当てはめていってますがどういうことですよね? <?php $dsn = 'mysql:dbname=test;host=localhost;charset=utf8'; $user = 'root'; $password = ''; $option = array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION); $pdo = new PDO($dsn, $user, $password, $option); $sql = "SELECT * FROM user_vitae WHERE user_id=? ORDER BY id ASC"; $stmt = $pdo->prepare($sql); $stmt->execute([$_SESSION['id']]); ?>
yambejp

2016/07/11 04:39

修正用にはすでにある文書のidもしくはユーザーidとタイトルの組み合わせを hiddenなどで引き継ぐわけです。 仮に自分がユーザーid=100番だとして、タイトル=テスト1をテストXに変えようとするなら INSERT 構文でテストXを投入すれば投入できてしまいます。 (たぶん今がこの状態) なので、修正の時は単純にUPDATE構文を発行してください
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問