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_string와 mysqli_real_escape_string와 mysql_query와 mysqli_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.