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

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

ただいまの
回答率

90.12%

MySQLのUPSERT文

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 427

いつもお世話になっております。

$idと$active_datetime_strがすでに存在していればUPDATE、存在していなければINSERTしたいです。下記コードを実行しても、常にINSERTしてしまいます。ご教示いただけますようよろしくお願いいたします。

CREATE TABLE `schedule` (
  `id` varchar(20) NOT NULL,
  `datetime` datetime NOT NULL,
  `schedule` tinyint(1) NOT NULL
) 
function update_schedule($dbh, $id, $set_schedule){
$active_datetime_str = get_active_datetime_str();
$cnt = count($active_datetime_str);
for ($i=0; $i < $cnt; $i++){
$sql = <<<SQL
INSERT INTO `schedule`
VALUES (:id, :active_datetime_str, :set_schedule)
ON DUPLICATE KEY UPDATE schedule = VALUES(schedule)
SQL;
// PDO::PARAM_STR-->プリペアドステートメント
$stmt = $dbh->prepare($sql);
// SQLに変数を代入
$stmt->bindValue(':id', $id, PDO::PARAM_STR);
$stmt->bindValue(':active_datetime_str', $active_datetime_str[$i], PDO::PARAM_STR);
$stmt->bindValue(':set_schedule', $set_schedule[$i], PDO::PARAM_STR);
if(!$stmt->execute()){
return FALSE;
}
}
return TRUE;
}
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

質問への追記・修正、ベストアンサー選択の依頼

  • papinianus

    2018/08/31 20:03

    yambejpさんが、まず、で書かれているとおりUNIQUE制約がなければそもそも動きません。UNIQUEかPRIMARYキー指定してからお試しください

    キャンセル

  • DaisukeKusakari

    2018/09/02 13:45

    ありがとうございます。ご指摘のお通り修正し、動作しました。

    キャンセル

回答 1

checkベストアンサー

+1

まず、ちゃんとdatetimeにunique属性をつけてますか?
また$idが$iに付随して変化しませんが大丈夫でしょうか?
datetimeを$active_datetime_str[$i]の重複でチェックするのに
datetime = VALUES(datetime)
をしているのも何をしたいのかわかりません
そしてprepare処理がまったくおかしいです

forで1文ずつSQLを実行するのは非効率的名のでまとめて処理するのを
おすすめします。(何万件も処理する場合は調整が必要)

 sample

  • テーブル作成とinsert
create table `schedule` (
  `id` varchar(20) NOT NULL,
  `datetime` datetime NOT NULL,
  `schedule` tinyint(1) NOT NULL,
  unique key(`id`,`datetime`)
);

insert into `schedule` values('honda', '2018-09-08 10:00:00', 1);
  • テーブル作成とinsert
insert into `schedule` values
('kagawa', '2018-09-08 10:00:00', 2),
('honda', '2018-09-09 10:00:00', 3),
('honda', '2018-09-08 10:00:00', 4)
on duplicate key update schedule=values(schedule)
  • 2のデータはidが違うので挿入
  • 3のデータはdatetimeが違うので挿入
  • 4のデータはidもdatetimeもかぶるので指定した4で更新

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/08/31 20:13 編集

    ああ、なんとなくわかりました
    idとdatatimeの組み合わせで複合uniqueにするのですね
    そうなると
    UPDATE `schedule` SET `schedule` = '2' WHERE `id`='honda' and `datetime` = '2018-09-08 10:00:00';
    です。

    これを1文でやるなら
    INSERT INTO `schedule` (`id`, `datetime`, `schedule`) VALUES ('honda', '2018-09-08 10:00:00', '1') ON DUPLICATE KEY UPDATE
    `schedule` = '2'
    とします
    (命題でなぜscheduleの値が1から2に変わっているか仕様がわかりませんが)

    キャンセル

  • 2018/09/02 13:43

    function update_schedule($dbh, $id, $set_schedule){
    $active_datetime_str = get_active_datetime_str();
    $cnt = count($active_datetime_str);
    for ($i=0; $i < $cnt; $i++){
    $sql = <<<SQL
    INSERT INTO `schedule`
    VALUES (:id, :active_datetime_str, :set_schedule)
    ON DUPLICATE KEY UPDATE schedule = VALUES(schedule)
    SQL;
    // PDO::PARAM_STR-->プリペアドステートメント
    $stmt = $dbh->prepare($sql);
    // SQLに変数を代入
    $stmt->bindValue(':id', $id, PDO::PARAM_STR);
    $stmt->bindValue(':active_datetime_str', $active_datetime_str[$i], PDO::PARAM_STR);
    $stmt->bindValue(':set_schedule', $set_schedule[$i], PDO::PARAM_STR);
    if(!$stmt->execute()){
    return FALSE;
    }
    }
    return TRUE;
    }

    おかげさまでここまででき、UPSERTされていることを確認できました。

    キャンセル

  • 2018/09/02 13:45

    >>forで1文ずつSQLを実行するのは非効率的名のでまとめて処理するのを
    おすすめします。(何万件も処理する場合は調整が必要)
    というのはバッチを使うということでしょうか。
    御厄介ついでにご教示いただけると幸いです。

    キャンセル

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

  • ただいまの回答率 90.12%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる