Прямо вот совсем недавно на стеке возник вопрос - как порционно загружать записи из CSV в БД? Вопрос-то простой, но дополнительным условием было - после окончания цикла while
нельзя делать дополнительный запрос на вставку.
Простое и понятное решение:
$handle = fopen(/* ... */);
$batch = [];
while (($data = fgetcsv($handle, 4096, ';')) !== false) {
$batch[] = processData($data);
if(100 === \count($batch)) {
runBatchInsert($batch);
$batch = [];
}
}
fclose($handle);
if ($batch) {
runBatchInsert($batch);
}
Как мы видим - здесь мы собираем записи в массив $batch
, и как только в этом массиве будет 100 элементов - выполняем запрос на вставку в функции runBatchInsert()
. Понятно, что после завершения цикла в $batch
могут находиться данные, которые также надо вставить, что мы и делаем вторым вызовом функции runBatchInsert()
.
Однако, по условию задачи мы не должны использовать второй вызов runBatchInsert()
. Это сделать вполне возможно, однако читабельность кода немного ухудшится, поэтому придется добавить немного комментариев, чтобы через месяц не забыть какого лешего это написано именно так, а не как у всех. В результате получаем такой вот код:
$handle = fopen(/* ... */);
$batch = [];
// запускаем "вечный" цикл
while (true) {
$data = fgetcsv($handle, 4096, ';');
// если данные есть - добавляем их в $batch
if (false !== $data) {
$batch[] = processData($data);
}
// если размер батча достиг лимита или мы больше не получили данных
if(100 === \count($batch) || false === $data) {
// в батче есть данные - вставляем
if ($batch) {
runBatchInsert($batch);
}
// данных больше нет - прерываем цикл
if (false === $data) {
break;
}
// очищаем батч
$batch = [];
}
}
fclose($handle);
Вы сами вольны выбирать какой из подходов использовать, но лично я использую первый.