PHP 배열을 통해 여러 행을 mysql에 삽입하십시오.


129

삽입 명령을 사용하여 PHP를 통해 큰 데이터 세트를 MySQL 테이블에 전달하고 1 마일 길이의 문자열 끝에 각 값을 추가 한 다음 쿼리를 통해 한 번에 약 1000 행을 삽입 할 수 있는지 궁금합니다. 그것을 실행. CodeIgniter 프레임 워크를 사용하고 있으므로 해당 기능도 사용할 수 있습니다.


Codeigniter의 다중 행 삽입에 대한 귀하의 질문에 따라 답변을주었습니다.
Somnath Muluk

) ... : @SomnathMuluk 내가이 질문에 대답 할 필요 했으므로하면서 그러나 그것은을되었습니다, 감사
toofarsideways

CodeIgniter의 insert_batch 함수를 사용하는 것이 좋습니다. 라이브러리를 사용하는 경우 항상 라이브러리의 장점과 코딩 표준을 활용하십시오.
Dewald Els

삽입 배치가 링크를 참조하는 가장 좋은 방법이라고 생각합니다. stackoverflow.com/questions/27206178/codeigniter-insert-batch
Syed Amir Bukhari

답변:


234

INSERTMySQL에서 여러 행으로 하나의 명령문을 구성하는 것이 INSERT행당 하나의 명령문 보다 훨씬 빠릅니다 .

즉, PHP에서 문자열 처리 문제가 발생하는 것처럼 들립니다. 실제로 언어 문제가 아니라 알고리즘 문제입니다. 기본적으로 큰 문자열로 작업 할 때 불필요한 복사를 최소화하려고합니다. 기본적으로 이는 연결을 피하려고 함을 의미합니다. 한 번에 수백 개의 행을 삽입하는 것과 같이 큰 문자열을 작성하는 가장 빠르고 메모리 효율적인 방법은 implode()함수 및 배열 할당 을 이용하는 것입니다 .

$sql = array(); 
foreach( $data as $row ) {
    $sql[] = '("'.mysql_real_escape_string($row['text']).'", '.$row['category_id'].')';
}
mysql_query('INSERT INTO table (text, category) VALUES '.implode(',', $sql));

이 방법의 장점은 지금까지 결합한 SQL 문을 각 연결로 복사하고 다시 복사하지 않는다는 것입니다. 대신, PHP는 명령문 에서 이것을 한 번 수행 implode()합니다. 이것은 승리입니다.

조합 할 열이 많고 하나 이상이 매우 긴 경우 동일한 작업을 수행하기 위해 내부 루프를 작성 implode()하고 values ​​절을 외부 배열에 할당하는 데 사용할 수도 있습니다 .


5
고마워요! 누군가 복사 할 계획이라면 함수 끝에 닫는 괄호가 없습니다. mysql_real_query ( 'INSERT INTO 테이블 값 (텍스트, 카테고리)'.implode ( ','. $ sql));
toofarsideways 2016

3
감사! 결정된. (나는 종종 그렇게한다 ...)
staticsan

1
쿼리는 정말 'INSERT INTO 테이블 (텍스트, 카테고리) 가치'.implode해야한다 ':( 끔찍한 디버깅 오전 4시 코딩 리드 한숨 (', '$ SQL.)
toofarsideways을

3
이 코드가 최신 프로젝트에 대한 솔루션을 만들 것이라고 생각합니다. 내 질문은, 이것이 SQL 주입에서 안전합니까? 내 계획은 밖으로 전환 할 수 있습니다 mysql_real_escape_stringmysqli_real_escape_stringmysql_querymysqli_query내가 MySQLi를 사용하고 있는데 이러한 PHP5의로 사용되지 않습니다있다. 많은 감사합니다!
wordman

2
mysql_*PHP에서 제거되었으므로 mysqli_*인터페이스 를 사용해야합니다 .
Rick James

60

codeigniter에서 다중 삽입 / 배치 삽입을 지원합니다. 나는 같은 문제가 있었다. 질문에 대답하기에는 너무 늦었지만 누군가를 도울 것입니다. 이것이 바로이 질문에 답하는 이유입니다.

$data = array(
   array(
      'title' => 'My title' ,
      'name' => 'My Name' ,
      'date' => 'My date'
   ),
   array(
      'title' => 'Another title' ,
      'name' => 'Another Name' ,
      'date' => 'Another date'
   )
);

$this->db->insert_batch('mytable', $data);

// Produces: INSERT INTO mytable (title, name, date) VALUES ('My title', 'My name', 'My date'), ('Another title', 'Another name', 'Another date')

2
이것이 mysql_query를 사용하는 대신 다중 행 삽입을 수행하는 가장 권장되는 방법이라고 생각합니다. 프레임 워크를 사용할 때는 항상 프레임 워크의 내장 기능을 사용하는 것이 좋습니다.
Praneeth Nidarshan

22

mysqli_stmt 클래스를 사용하여 하나의 행을 삽입하기 위해 쿼리를 준비한 다음 데이터 배열을 반복 할 수 있습니다. 다음과 같은 것 :

$stmt =  $db->stmt_init();
$stmt->prepare("INSERT INTO mytbl (fld1, fld2, fld3, fld4) VALUES(?, ?, ?, ?)");
foreach($myarray as $row)
{
    $stmt->bind_param('idsb', $row['fld1'], $row['fld2'], $row['fld3'], $row['fld4']);
    $stmt->execute();
}
$stmt->close();

여기서 'idsb'는 바인딩하는 데이터 유형입니다 (int, double, string, blob).


6
최근에 여기에 언급 된대로 대량 삽입과 준비된 삽입 문을 비교하는 벤치 마크를 실행했습니다. 약 500 개의 인서트의 경우, 준비된 인서트 방법은 2.6-4.4 초에서 완료되고 벌크 인서트 방법은 0.12-0.35 초에서 완료되었습니다. 필자는 mysql이 이러한 준비된 명령문을 함께 "벌크 (bulk)"하고 대량 삽입 (bulk insert)과 마찬가지로 수행한다고 생각했지만 기본 설정에서는 성능 차이가 상당히 크다. (자동 커밋을 방지하기 위해 모든 벤치마킹 된 쿼리는 각 테스트마다 단일 트랜잭션 내에서 실행되었습니다)
Motin

16

나는 이것이 오래된 쿼리라는 것을 알고 있지만, 나는 단지 읽고 있었고 다른 곳에서 찾은 것을 추가 할 것이라고 생각했다.

PHP 5의 mysqli는 위의 답변에 대한 삽입 시간을 단축 할 수있는 좋은 기능을 갖춘 ojbect입니다.

$mysqli->autocommit(FALSE);
$mysqli->multi_query($sqlCombined);
$mysqli->autocommit(TRUE);

많은 행을 삽입 할 때 자동 커밋을 끄면 삽입 속도가 빨라지므로 끄고 위에서 언급 한대로 실행하거나 세미 콜론으로 구분 된 많은 삽입 문 인 문자열 (sqlCombined)을 만들면 다중 쿼리가 잘 처리됩니다.

이것이 누군가가 시간을 절약하는 데 도움이되기를 바랍니다 (검색 및 삽입!)

아르 자형


이것은 내가 당신의 아이디어를 사용하여 얻은 오류입니다. "치명적인 오류 : 30 번째 줄의 /homepages/25/d402746174/htdocs/MoneyMachine/saveQuotes.php에서 null에 멤버 함수 autocommit () 호출"
user3217883

8

항상 mysql을 사용할 수 있습니다 LOAD DATA:

LOAD DATA LOCAL INFILE '/full/path/to/file/foo.csv' INTO TABLE `footable` FIELDS TERMINATED BY ',' LINES TERMINATED BY '\r\n' 

많은 INSERT명령문을 사용하지 않고 대량 삽입을 수행 합니다.


나는 그것을 조사했지만 데이터를 삽입하기 전에 조작해야합니다. 그것은 1400 x 1400 int 값의 Cartesian 곱으로 주어졌으며 많은 값은 0입니다. 대량 삽입 반대로 나는 때문에 삽입의 필요성을 공간을 절약하기 위해 중간 테이블을 사용하여 많은 관계로 많은 것을 변환해야
toofarsideways을

csv 파일을 조작하고 데이터를로드하는 mysql 문을 호출 한 후 언제든지 csv 파일을 생성 할 수 있습니다
Alexander Jardim

경로가 SQL 서버가 아닌 SQL 클라이언트의 로컬 경로임을 아는 것이 도움이된다고 생각합니다. 파일이 서버에 업로드 된 후 파일을 읽습니다. 파일이 이미 서버에 있어야한다고 생각했지만 그렇지 않습니다. 서버에 이미있는 경우 LOCAL비트를 제거하십시오 .
Kyle

5

글쎄, 당신은 1000 개의 쿼리 호출을 실행하고 싶지 않지만 이것을하는 것이 좋습니다 :

$stmt= array( 'array of statements' );
$query= 'INSERT INTO yourtable (col1,col2,col3) VALUES ';
foreach( $stmt AS $k => $v ) {
  $query.= '(' .$v. ')'; // NOTE: you'll have to change to suit
  if ( $k !== sizeof($stmt)-1 ) $query.= ', ';
}
$r= mysql_query($query);

데이터 소스에 따라 배열을 채우는 것은 파일을 열고를 통해 배열에 내용을 덤프하는 것만 큼 쉽습니다 file().


1
쿼리 위로 이동하여 if ($ k> 0)과 같이 변경하면 더 깨끗합니다.
cherouvim

@cherouvim ... 글쎄, 당신은 그것에 대해 맞습니다. 입력 해 주셔서 감사합니다. 내가 제공 한 예를 다시 읽으면서 요점을 알 수 없습니다. 파스 빈 등을 통해 정교하게 관리 할 수 ​​있습니까? 감사합니다
bdl

3
$query= array(); 
foreach( $your_data as $row ) {
    $query[] = '("'.mysql_real_escape_string($row['text']).'", '.$row['category_id'].')';
}
mysql_query('INSERT INTO table (text, category) VALUES '.implode(',', $query));

1

codeigniter에서 여러 가지 방법으로 할 수 있습니다.

첫 번째 루프

foreach($myarray as $row)
{
   $data = array("first"=>$row->first,"second"=>$row->sec);
   $this->db->insert('table_name',$data);
}

두 번째 -삽입 배치

$data = array(
       array(
          'first' => $myarray[0]['first'] ,
          'second' => $myarray[0]['sec'],
        ),
       array(
          'first' => $myarray[1]['first'] ,
          'second' => $myarray[1]['sec'],
        ),
    );

    $this->db->insert_batch('table_name', $data);

세 번째 방법-다중 값 전달

$sql = array(); 
foreach( $myarray as $row ) {
    $sql[] = '("'.mysql_real_escape_string($row['first']).'", '.$row['sec'].')';
}
mysql_query('INSERT INTO table (first, second) VALUES '.implode(',', $sql));

1

이 질문에 대답하기에는 너무 늦었지만. 여기에 같은 대답이 있습니다.

CodeIgniter를 사용하는 경우 query_builder 클래스에 정의 된 내장 메소드를 사용할 수 있습니다.

$ this-> db-> insert_batch ()

제공 한 데이터를 기반으로 삽입 문자열을 생성하고 쿼리를 실행합니다. 배열이나 객체를 함수에 전달할 수 있습니다. 다음은 배열을 사용하는 예입니다.

$data = array(
    array(
            'title' => 'My title',
            'name' => 'My Name',
            'date' => 'My date'
    ),
    array(
            'title' => 'Another title',
            'name' => 'Another Name',
            'date' => 'Another date'
    )

);

$this->db->insert_batch('mytable', $data);
// Produces: INSERT INTO mytable (title, name, date) VALUES ('My title', 'My name', 'My date'),  ('Another title', 'Another name', 'Another date')

첫 번째 매개 변수는 테이블 이름을 포함하고 두 번째 매개 변수는 값의 연관 배열입니다.

query_builder에 대한 자세한 내용은 여기를 참조 하십시오.


0

다음과 같이 사용되는 여러 줄을 수행하는 클래스를 만들었습니다.

$pdo->beginTransaction();
$pmi = new PDOMultiLineInserter($pdo, "foo", array("a","b","c","e"), 10);
$pmi->insertRow($data);
// ....
$pmi->insertRow($data);
$pmi->purgeRemainingInserts();
$pdo->commit();

여기서 클래스는 다음과 같이 정의됩니다.

class PDOMultiLineInserter {
    private $_purgeAtCount;
    private $_bigInsertQuery, $_singleInsertQuery;
    private $_currentlyInsertingRows  = array();
    private $_currentlyInsertingCount = 0;
    private $_numberOfFields;
    private $_error;
    private $_insertCount = 0;

    /**
     * Create a PDOMultiLine Insert object.
     *
     * @param PDO $pdo              The PDO connection
     * @param type $tableName       The table name
     * @param type $fieldsAsArray   An array of the fields being inserted
     * @param type $bigInsertCount  How many rows to collect before performing an insert.
     */
    function __construct(PDO $pdo, $tableName, $fieldsAsArray, $bigInsertCount = 100) {
        $this->_numberOfFields = count($fieldsAsArray);
        $insertIntoPortion = "REPLACE INTO `$tableName` (`".implode("`,`", $fieldsAsArray)."`) VALUES";
        $questionMarks  = " (?".str_repeat(",?", $this->_numberOfFields - 1).")";

        $this->_purgeAtCount = $bigInsertCount;
        $this->_bigInsertQuery    = $pdo->prepare($insertIntoPortion.$questionMarks.str_repeat(", ".$questionMarks, $bigInsertCount - 1));
        $this->_singleInsertQuery = $pdo->prepare($insertIntoPortion.$questionMarks);
    }

    function insertRow($rowData) {
        // @todo Compare speed
        // $this->_currentlyInsertingRows = array_merge($this->_currentlyInsertingRows, $rowData);
        foreach($rowData as $v) array_push($this->_currentlyInsertingRows, $v);
        //
        if (++$this->_currentlyInsertingCount == $this->_purgeAtCount) {
            if ($this->_bigInsertQuery->execute($this->_currentlyInsertingRows) === FALSE) {
                $this->_error = "Failed to perform a multi-insert (after {$this->_insertCount} inserts), the following errors occurred:".implode('<br/>', $this->_bigInsertQuery->errorInfo());
                return false;
            }
            $this->_insertCount++;

            $this->_currentlyInsertingCount = 0;
            $this->_currentlyInsertingRows = array();
        }
        return true;
    }

    function purgeRemainingInserts() {
        while ($this->_currentlyInsertingCount > 0) {
            $singleInsertData = array();
            // @todo Compare speed - http://www.evardsson.com/blog/2010/02/05/comparing-php-array_shift-to-array_pop/
            // for ($i = 0; $i < $this->_numberOfFields; $i++) $singleInsertData[] = array_pop($this->_currentlyInsertingRows); array_reverse($singleInsertData);
            for ($i = 0; $i < $this->_numberOfFields; $i++)     array_unshift($singleInsertData, array_pop($this->_currentlyInsertingRows));

            if ($this->_singleInsertQuery->execute($singleInsertData) === FALSE) {
                $this->_error = "Failed to perform a small-insert (whilst purging the remaining rows; the following errors occurred:".implode('<br/>', $this->_singleInsertQuery->errorInfo());
                return false;
            }
            $this->_currentlyInsertingCount--;
        }
    }

    public function getError() {
        return $this->_error;
    }
}

0

여러 행의 데이터를 삽입하려면 codeigniter에서 배치 삽입을 사용하십시오.

$this->db->insert_batch('tabname',$data_array); // $data_array holds the value to be inserted

0

나는 당신이 쉽게 사용할 수있는이 간단한 기능을 만들었습니다. 삽입 데이터 data array에 대해 table-name ($tbl)테이블 필드 를 전달해야합니다 .($insertFieldsArr)($arr)

insert_batch('table',array('field1','field2'),$dataArray);

    function insert_batch($tbl,$insertFieldsArr,$arr){ $sql = array(); 
    foreach( $arr as $row ) {
        $strVals='';
        $cnt=0;
        foreach($insertFieldsArr as $key=>$val){
            if(is_array($row)){
                $strVals.="'".mysql_real_escape_string($row[$cnt]).'\',';
            }
            else{
                $strVals.="'".mysql_real_escape_string($row).'\',';
            }
            $cnt++;
        }
        $strVals=rtrim($strVals,',');
        $sql[] = '('.$strVals.')';
    }

    $fields=implode(',',$insertFieldsArr);
    mysql_query('INSERT INTO `'.$tbl.'` ('.$fields.') VALUES '.implode(',', $sql));
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.