-2

データをかなり速く挿入しようとすると失敗するため、データをバッチに分割する php 関数を作成しようとしています。

何千ものユーザーデータのレコードを同じデータベースの別の形式に挿入し、後で別のデータベースにエクスポートしようとしています。ただし、クエリは失敗します。

以下のコメントと回答に基づいて、コードを次のように更新しました。それでも失敗します。

値を挿入するコード:

        function insertUsers( $users ){
            error_reporting(E_ALL);
            ini_set('display_errors',1);

            global $pdo;
            //insert into database
            $i = 0;
            $base = 'INSERT INTO tth_user_accounts (user_login, user_pass, user_email, user_registered,
                      user_firstname, user_lastname ) VALUES ';
            $sql = '';

            var_dump($users);

            while( $i < count( $users ) ){
                $sql = $sql . ' ("' .
                    $users[$i]['user_login'] . '", "' .
                    $users[$i]['user_pass'] . '", "' .
                    $users[$i]['user_email'] . '", "' .
                    $users[$i]['user_registered'] . '", "' .
                    $users[$i]['meta_value']['first_name'] . '", "' .
                    $users[$i]['meta_value']['last_name'] . '")';

                if (!( $i % 25 === 0 )){
                    $sql = $sql . ', ';
                }

                if ($i % 25 === 0) {
                    //execute $base + $query here
                    $sql = $base . $sql;

                    $query = $pdo->prepare( $sql );
                    echo 'check query: <br />';
                    print_r( $query );

                    if( $query->execute() ){
                        echo '50 users succesfully added to the database';
                    } else {
                        echo 'Query failed: ';
                        print_r( $pdo->errorInfo() );
                        echo '<br />';
                    }
                    $sql = ''; //Re-init query string
                }
                $i++;
            }

            if ( strlen( $sql ) > 0 ) {  // Execute remainder, if any
                //execute $base + $query here
                $sql = $base . $sql;

                $query = $pdo->prepare( $sql );
                echo 'check query: <br />';
                print_r($query);

                if( $query->execute() ){
                    echo 'User succesfully added to the database';
                } else {
                    echo 'Query failed: ';
                    print_r( $pdo->errorInfo() );
                    echo '<br />';
                }
            }
        }

クエリを確認してください: PDOStatement Object ( [queryString] => INSERT INTO tth_user_accounts (user_login, user_pass, user_email, user_registered, user_firstname, user_lastname ) VALUES ("John Smith", "4\/\/350M3 P4sS\/\/0r|)", "john.smith@greatmail.com", "2013-04-11 11:18:58", "John", "Smith") )

クエリに失敗しました:Array ( [0] => 00000 [1] => [2] => )

%25とで試してみましたが%50、どちらも機能しません。勝利につながるはずの00000 エラーが発生し続けます(成功、私にとってはまだ失敗しますが、DBには何もありません)

時間があれば手動で行いますが、これは 1 回限りのイベントではないため、この問題の解決策が必要です。これを繰り返してクエリを次々に実行できるように、クエリをバッチに分割する良い方法はありますか? 私はすでにSO(および他の場所)に関するたくさんの質問を見てきましたが、私のニーズに合ったものを見つけることができません.

更新- 回答済みです。以下に示すように小さな変更が必要です。

if (!( $i % 25 === 0 )){
    if(!( $i == ( count( $users ) - 1 ))){
        $sql = $sql . ', ';
    }
}
4

4 に答える 4

2

関数と混合PDOしていmysql_ます。1 つを選択し、それぞれのライブラリのエラー処理に従います。

$sql正しくフォーマットされているかどうかを確認するために、自分で印刷することも有益です。さらに、POSTed データを処理している場合は、準備済みステートメントを使用する必要があります。

于 2013-05-06T13:28:36.720 に答える
1

デフォルトで 1Mb に設定されているmax_allowed_pa​​cket値を増やす必要がある場合があります。クエリをバッチで分割したい場合は、モジュラス演算子を使用して行うことができます。

$base = 'INSERT INTO ...';
$sql = '';
while( $i < count( $users ) ){
    $sql = $sql . ' ("' ... //etc.
    if ($i % 50 === 0) {
        //execute $base + $qry here
        $sql = ''; //Re-init query string
    }
}
if (strlen($qry)>0) {  // Execute remainder, if any
    //execute $base + $query here
}

または配列として(ここで説明):

$base = 'INSERT INTO ...';
$sql = array();
while( $i < count( $users ) ){
    $sql[] = ' ("' ... //etc.
    if ($i % 50 === 0) {
        //execute $base + implode(',', $sql) here
       $sql = array(); //Re-init query string
    }
}
if (sizeof($qry)>0) {  // Execute remainder, if any
    //execute $base + implode(',', $sql) here
}

また、 SQL インジェクションに対して脆弱にならないように、準備済みステートメントを 正しく使用していることを確認してください。

最後に:エラー報告を有効にする必要があるかもしれません。エラー報告を有効にした後もまだ沈黙している場合 (例)、MySQL を厳密モードerror_reporting(-1);に設定する必要があるかもしれません(それが役立つかどうかはわかりません)。それでも失敗する場合は、黙ってバグレポートを提出してください。

編集 ああ、あなたがミキシングmysql_とPDOを行っているという事実を見逃しました。それがおそらくエラーが表示されない理由です... D'uh。PDO エラー処理に関するマニュアルを読んでください。

@Downvoters: 少なくとも反対票を投じている場合は、理由についてコメントを残す良識があります。

于 2013-05-06T13:28:54.300 に答える
0

1つのステートメントとして実行したい理由はありますか? ユーザーを繰り返し処理して、次のようなものをそれぞれ挿入してみませんか。

while($i < count( $users )) {

    $sql = 'INSERT INTO tth_user_accounts (user_login, user_pass, user_email, user_registered, user_firstname, user_lastname ) VALUES ';

    $sql = $sql + "(";
    $sql = $sql + "'" . $users[$i]['user_login'] . '",';
    $sql = $sql + "'" . $users[$i]['user_pass'] . '",';
    $sql = $sql + "'" . $users[$i]['user_email'] . '",';
    $sql = $sql + "'" . $users[$i]['user_registered'] . '",';
    $sql = $sql + "'" . $users[$i]['meta_value']['first_name'] . '",';
    $sql = $sql + "'" . $users[$i]['meta_value']['last_name'] . '"';
    $sql = $sql + ")";


    $query = $pdo->prepare( $sql );

    if( $query->execute() ){
        echo 'User succesfully added to the database';
    } else {
        die ("Query failed: " . $pdo->errorInfo());
    }
}

さらに良いのは、ステートメントを一度準備してからパラメーターをバインドすることです。RobIII が指摘したように、SQL ステートメントを文字列として構築することで SQL インジェクションの脆弱性を導入できるため、代わりに次のようにすることができます。

$sql = 'INSERT INTO tth_user_accounts (user_login, user_pass, user_email, user_registered, user_firstname, user_lastname) ';
$sql += ' VALUES (:user_login, :user_pass, :user_email, :user_registered, :user_firstname, :user_lastname)';

$query = $pdo->prepare( $sql );

while ($i < count($users)) {

    $query->bindParam(":user_login", $users[$i]['user_login']);
    $query->bindParam(":user_pass", $users[$i]['user_pass']);
    $query->bindParam(":user_email", $users[$i]['user_email']);
    $query->bindParam(":user_registered", $users[$i]['user_registered']);
    $query->bindParam(":user_firstname", $users[$i]['user_firstname']);
    $query->bindParam(":user_lastname", $users[$i]['user_lastname']);

    if( $query->execute() ){
        echo 'User succesfully added to the database';
    } else {
        die ("Query failed: " . $pdo->errorInfo());
    }
}
于 2013-05-06T13:40:30.463 に答える
-2

発生する可能性のある別の問題は、ユーザーの名前/情報に無効な文字が含まれている可能性があり、コマンドが強制終了される可能性があるという単純な事実です。たとえば、姓が「O'Maley」であるとします。値の文字列を作成し、名前を引用符で囲むと、次のようになります。

「オマリー」

私は約 8 年前にこれに似た問題に遭遇し、データ内の特定の値を検証する必要がありました。それが見つかったら、それぞれの値を修正する方法を理解してから、バッチ モードに戻ります。

また、行の残りがコメントであることを示す「--」の偽の/悪い値の偽の値を提供する誰かを検討してください...または「;」さえあります ステートメントの終わりを示します。それはおそらくあなたが遭遇しているものです。

RobIIIが応答したように、応答が速すぎたので、一度に1つずつテストするのではなく、データにクエリを実行して、データ内のそのような異常/悪いエスケープポストを調べます. 挿入を試す前に、必要なものを修正してください。

于 2013-05-06T13:39:26.717 に答える