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

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

ただいまの
回答率

87.79%

PHPでSQLを実行するときに、SQLに変数を使いたい

受付中

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 557

score 16

実現したいこと

以下my_update_yasai()という関数で、$updatesの値を保存したいです。

発生している問題

保存が実行されません。

$sqlの変数が原因ではないか?と、
これから書くような根拠から推察していますが、
その解決策がわからない状況です。
宜しくお願い致します。

該当のソースコード

まず以下$updatesが保存する情報でして、
これをループしてmy_update_yasai()を実行していく流れです。

// 保存を実行
$updates = [
    ['yasai_name'=>'野菜A','yasai_count'=>64,'yasai_data'=>'野菜Aはとても甘い'],
    ['yasai_name'=>'野菜B','yasai_count'=>45,'yasai_data'=>'野菜Bはとても辛い'],
    ['yasai_name'=>'野菜C','yasai_count'=>78,'yasai_data'=>'野菜Cはとても苦い'],
];
foreach( $updates as $update ) {
    my_update_yasai( 'insert', $update );
}


保存の関数がこちらですが、実現できない状況です。

// 保存の関数
function my_update_yasai( $type, $update, $targets=null ) {

    global $wpdb;

    // 更新する情報
    $table = $wpdb->yasai_table;
    $yasai_time = $update['yasai_time'] ?? 0000;
    $yasai_name = $update['yasai_name'] ?? 'nothing';
    $yasai_count= $update['yasai_count'] ?? 0000;
    $yasai_data = $update['yasai_data'] ?? 'nothing';

    // 更新する値
    $data = [];
    if ( isset($yasai_time) ) {
        $data['yasai_time'] = $yasai_time;
    }    
    if ( isset($yasai_name) ) {
        $data['yasai_name'] = $yasai_name;
    }    
    if ( isset($yasai_count) ) {
        $data['yasai_count'] = $yasai_count;
    }
    if ( isset($yasai_data) ) {
        $data['yasai_data'] = $yasai_data;
    }

    // $data の値の書式
    $format = [];
    if ( isset($yasai_time) ) {
        $format[] = '%d';
    }    
    if ( isset($yasai_name) ) {
        $format[] = '%s';
    }    
    if ( isset($yasai_count) ) {
        $format[] = '%d';
    }
    if ( isset($yasai_data) ) {
        $format[] = '%s';
    }

    if ( $type == 'insert' ) {

        // $updateで指定した情報を保存する処理
        $data_keys = rtrim(implode(",",array_keys($data)));
        $data_vals = rtrim(implode(",",$data));
        $formats = rtrim(implode(",",$format));        
        $sql = $wpdb->prepare("INSERT INTO $wpdb->yasai_table ( $data_keys ) values ( $formats )", $data_vals);
        var_dump($sql); // 【 ← 追記その1 】
        $wpdb->query($sql);

    }elseif ( $type == 'update' ) {

        // $targetsで指定した行に対して、$updateで指定した情報を上書きする処理

    }    
}

試したこと

my_update_yasai()で、以下$sql部分の変数が
正しく展開できていないのではないかと考えています。

$sql = $wpdb->prepare("INSERT INTO $wpdb->yasai_table ( $data_keys ) values ( $formats )", $data_vals);


そこで$data_keys,$formats,$data_valsの各変数を
var_dumpしたところ以下の結果を得ました。

string(44) "yasai_time,yasai_name,yasai_count,yasai_data"
string(11) "%d,%s,%d,%s"
string(49) "1,野菜テスト,111,野菜テストのデータ"


上の値をvar_dumpするコードは次の通りで、
これは該当のソースコードのループをやめたものとなっています。

<?php
$yasai_time = 1;
$yasai_name = '野菜テスト';
$yasai_count = 111;
$yasai_data = '野菜テストのデータ';

// 更新する値
$data = [];
if ( isset($yasai_time) ) {
    $data['yasai_time'] = $yasai_time;
}    
if ( isset($yasai_name) ) {
    $data['yasai_name'] = $yasai_name;
}    
if ( isset($yasai_count) ) {
    $data['yasai_count'] = $yasai_count;
}
if ( isset($yasai_data) ) {
    $data['yasai_data'] = $yasai_data;
}

// $data の値の書式
$format = [];
if ( isset($yasai_time) ) {
    $format[] = '%d';
}    
if ( isset($yasai_name) ) {
    $format[] = '%s';
}    
if ( isset($yasai_count) ) {
    $format[] = '%d';
}
if ( isset($yasai_data) ) {
    $format[] = '%s';
}

$data_keys = rtrim(implode(",",array_keys($data)));
$formats = rtrim(implode(",",$format));    
$data_vals = rtrim(implode(",",$data));
var_dump( $data_keys );
var_dump( $formats );
var_dump( $data_vals );


さて上のvar_dumpを確認できたのでその値を使い、
my_update_yasai()の変数をやめたバージョンとして次の
my_update_yasai_test()のように直接入れた関数を作ってみますと、
保存が実現できました。

// 新規保存テスト
function my_update_yasai_test( $yasai_name, $yasai_count, $yasai_data ) {
    global $wpdb;
    $sql = $wpdb->prepare("INSERT INTO $wpdb->yasai_table (yasai_name, yasai_count, yasai_data) values (%s, %d, %s)", $yasai_name, $yasai_count, $yasai_data);
    var_dump($sql); // 【 ← 追記その2 】
    $wpdb->query($sql);
}
my_update_yasai_test( '野菜Z', 77, '野菜Zはかなりレア' );


以上のことから推察するに、
該当のソースコードの$sqlの変数が原因ではないか?と考えています。

しかし、my_update_yasai()でできず、その変数部分を直接書いたmy_update_yasai_test()でできて、かといってmy_update_yasai()の変数をvar_dumpするとmy_update_yasai_test()に直接書いた値と同じですから、これ以上なにをすればいいのかと行き詰ってしまいました。

アドバイス頂けましたら幸いです。
宜しくお願い致します。

追記

上のそれぞれの関数で
var_dump($sql); // 【 ← 追記その1 】
var_dump($sql); // 【 ← 追記その2 】
というvar_dumpを追記しました。

その結果は以下です。

↓うまくいってる場合のmy_update_yasai_test()var_dump($sql)
string(126) "INSERT INTO wp_yasai_table (yasai_name, yasai_count, yasa_data) values ('野菜テスト', 111, '野菜テストのデータ')"

↓ダメな場合のmy_update_yasai()var_dump($sql)
string(0) ""
string(0) ""
string(0) ""

後者でなぜ空になるのか…かなり戸惑っています。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

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

  • tabuu

    2020/01/23 17:20

    パラメータではなく「$sql」という変数(文字列)は上手くいっている場合とダメな場合とそれぞれどうなっていますか?

    キャンセル

  • marusankakun

    2020/01/23 17:34

    たしかに、var_dumpするなら「$sql」の方でしたね。ところで、ダメな場合の結果がかなり意味不明なことになりました。以下の通りです。なぜ空に…。

    ↓うまくいってる場合の「my_update_yasai_test()」でvar_dump($sql)
    string(126) "INSERT INTO wp_yasai_table (yasai_name, yasai_count, yasa_data) values ('野菜テスト', 111, '野菜テストのデータ')"

    ↓ダメな場合の「my_update_yasai()」でvar_dump($sql)
    string(0) ""
    string(0) ""
    string(0) ""

    キャンセル

  • tabuu

    2020/01/24 08:12

    上手くいっているときは「yasai_time」がありませんが、追加したらどうなるでしょうか?

    キャンセル

回答 2

0

string(49) "1,野菜テスト,111,野菜テストのデータ"


上記は、以下の様に、文字列としてシングルクオート(')で括ったものにならないとエラーになるはずです。

string(49) "1,'野菜テスト',111,'野菜テストのデータ'"

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2020/01/23 14:06

    どう解決するのがベストでしょうか?

    頂いたご指摘についての自分なりの解決策を考えますと以下の変更かと思ったのですが、スマートじゃないというかなんというか…、微妙ですよね?

    そもそも以下は空が返ってしまって解決できなかったので、よかったら具体的な方針を伺えればと。


    $data_vals = rtrim(implode(",",$data));

    ↓ 以下に変更

    $data_vals = my_implode($data);
    function my_implode( $arr ){
    $unit = '';
    foreach ( $arr as $v ) {
    $type = gettype( $v );
    if ( $type == 'string' ) {
    $unit .= '"' . $v . '"'; // シングルクオートで括っているつもり
    } elseif ( $type == 'integer' ) {
    $unit .= $v;
    }
    $unit .= ',';
    }
    return rtrim(",",$unit); // 空が返ってしまう?
    }

    キャンセル

  • 2020/01/23 15:15

    空が返ってくるというより、エラーで実行されていないのでしょう。
    例外を拾うようにした方が良いかと思います。
    PHPは詳しくないので、識者の回答をお待ち下さい。

    キャンセル

  • 2020/01/23 16:57

    なるほど。情報ありがとうございました。

    キャンセル

0

これではダメなのでしょうか?

$insert="INSERT INTO $wpdb->yasai_table ( $data_keys ) values ( $formats )";
$sql = call_user_func_array([$wpdb,"prepare"],array_merge($insert,explode(",",$data_vals)));


※調整

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2020/01/23 15:22 編集

    修正しました

    キャンセル

  • 2020/01/23 16:56

    ありがとうございます。ご修正いただいたそちらですが

    call_user_func_array() expects parameter 2 to be array, null given in

    というエラーでした。よく見ますとarray_mergeの引数$insertがテキストであるためarray_mergeできず、よって上のエラーが出ているのではないかと。array_mergeはarray_marge(配列,配列)のように、引数には配列しか使えないみたいですね。

    なのでarray_margeでなくテキストが追加できるarray_pushにしようと思ったのですが、でも、array_pushはarray_push(配列,文字列)という順で与えなければなりませんから、今回使えないですよね。これは一体どうすれば…

    もしよい書き方ございましたらお知恵を拝借できませんでしょうか。

    キャンセル

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

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

関連した質問

同じタグがついた質問を見る