How to use batch update/insert sql using codeigniter? - php

in this example.. how can i simplified and fasten up the update and insert of data in the database?
//if count($arr_list['sample_element1'] is 500+++ or more records
$i =0;
while ($i < count($arr_list['sample_element1'])) {
$update_db= array('column1' => $arr_list['sample_element1'][$i],'column2' => $arr_list['sample_element2'][$i]);
$this->db->update('sample_table',$update_db);
$i++;
}
if the record to be save is over 1000 data...it will take about sometime to finish the process.. thank in advance.. =)

use batch_update
$this->db->update(table_name,array,where_key_word);
here table_name = your table name
and array = an array containing multiple associative array
and where_key_word = the column which should be used in where condition
also read this question thread for more information
batch updating thousands of element together may create performance issue.Better split them up and update by smaller batch.Also use transactions so that if any of the update fails the whole update procedure can be rolled back

Taking #AL-zami's answer you're looking for this
$data = [];
$this->db->trans_start();
foreach($arr_list as $item)
{
$data[] = [
'column1' => $item['element1'],
'column2' => $item['element2'],
'column3' => $item['element3']
];
}
$this->db->update_batch('mytable', $data, 'column1');
$this->db->trans_complete();
Where 'column1' is the column used for the "WHERE" condition.

Related

Multiple/same data

I try to make condition where i delete data before insert data to prevent multiple data but it didnt work | even the data in table become empty || 'id_lokasi' is my column name in table - database
$factpelanggan4 = DB::connection('clickhouse')
->select("SELECT t.id_tahun, l.id_lokasi, stage.jml_pelanggan
from dim_tahun t
inner join stage_pelanggan stage on t.tahun = stage.years
inner join dim_lokasi l on stage.city_id = l.id_kota
WHERE (stage.country_id = l.id_negara)
ORDER BY t.id_tahun ASC , l.id_lokasi ASC, stage.jml_pelanggan ASC
");
foreach ($factpelanggan4 as $value) {
$tahun_id[] = $value['t.id_tahun'];
$lokasi_id[] = $value['l.id_lokasi'];
$jml[] = $value['stage.jml_pelanggan'];
}
DB::connection('clickhouse')->table('fakta_pelanggan')->where('id_lokasi', $lokasi_id)->delete();
//DB::connection('clickhouse')->table('fakta_pelanggan')->where('id_lokasi', Not Null)->delete();
foreach ($factpelanggan4 as $key => $value) {
$arrayInsert = array(
'id_tahun' => $tahun_id[$key],
'id_lokasi' => $lokasi_id[$key],
'jml_pelanggan' => $jml[$key],
);
DB::connection('clickhouse')->table('fakta_pelanggan')->insert($arrayInsert);
$key++;
}
You should avoid deleting if you're just inserting, or deleting then inserting. If something goes wrong, you'd be left with no data similar to a truncate. What you really should be doing is inserting or updating.
You can do this manually, selecting, then either inserting or updating, separately. Or you can use firstOrCreate, firstOrNew, updateOrCreate or similar approaches.
Since you're working on multiple records at once, you might try an upsert for updating/inserting multiple records at once:
https://laravel.com/docs/9.x/eloquent#upsert
$toInsertOrUpdate = [];
foreach ($factpelanggan4 as $key => $value) {
// I don't quite follow your looping logic.
// What you wrote with $key++ after each loop before
// will be completely ignored since each loop overwrites it.
// This is a factored version of what you wrote before.
// Please double check it to make sure it does what you want.
$toInsertOrUpdate[] = [
'id_tahun' => $tahun_id[$key],
'id_lokasi' => $lokasi_id[$key],
'jml_pelanggan' => $jml[$key],
];
}
// these columns together identify duplicate records.
$uniqueIdentifyingColumns = ['id_tahun','id_lokasi','jml_pelanggan'];
// when a duplicate record is found, only these columns will be updated
$columnsToUpdateOnDuplicate = ['id_tahun','id_lokasi','jml_pelanggan'];
$tbl = DB::connection('clickhouse')->table('fakta_pelanggan');
$tbl->upsert(
$toInsertOrUpdate,
$uniqueIdentifyingColumns,
$columnsToUpdateOnDuplicate
);

Getting a an array from for loop and use another for loop with that array in PHP

I have a for loop, and will form two arrays in the loo
foreach ($data as $key => $value) {
........
........
$user_insert[] = [
'keyy' => $value,
'key' => $value,
....
...
...
];
$someArray1[] = [
/*'user_id' => $insert_id,*/
'key1' => $value1,
'keyy' => $value,
.......
........
];
}
the count of $user_insert[] array is 4, the count of $someArray1 is 15.
after this for loop, I need to insert $user_insert array data to the database and use that inserted_id to insert next array $someArray1
foreach($user_insert as $insert_user){
$unique_user_insert = array_unique($insert_user);
//dd($unique_user_insert);
$insert_id = DB::table('users')->insertGetId($unique_user_insert);
foreach ($someArray1 as $someArray) {
$someArray['user_id'] = $insert_id;
DB::table('table_name')->insert($someArray);
}
}
So the problem here is the data in the second loop is inserting 60 times(4 * 15). I need to insert only 15 rows.
The data($someArray1) is coming from the first for loop, but I need to add a user_id to that array which I get after the insert operation in second for loop.
So how can i insert only 15 rows.
I'm going to assume that you are able to access your $someArray1 using the $insert_id value to find the appropriate user data.
foreach($user_insert as $insert_user){
$unique_user_insert = array_unique($insert_user);
$insert_id = DB::table('users')->insertGetId($unique_user_insert);
// Get the user information you need as $someArray1 should be user_id=>data
$userData = $someArray[$insert_id];
$userData['user_id'] = $insert_id;
// No need for an inner loop, just access the necessary properties of the loop you created earlier.
DB::table('table_name')->insert($userData);
}
Your tags indicate that you are using Laravel 5 too. If you are using the eloquent ORM, some of the insertion and ID retrieval can be cleaned up by creating Models for your DB tables.
Actually, each time you process a line from $user_insert, you loop over $someArray1 instead of fetching just the line you need.
The thing is to understand the line you need. As much as I can understand your piece of code, I would say the easiest (most readable) way of doing it is by using a for loop, not a foreach one :
for( $i = 0, $iMax = count( $user_insert ); $i < $iMax; ++$i ){
$insert_user = $user_insert[$i];
// Put your `$user_insert` insert code here
$someArray1[$i]['user_id'] = $insert_id;
DB::table('table_name')->insert( $someArray[$i] ); // Note the [$i] here
}
You also may do that with foreach by requesting indices :
foreach( $user_insert as $i => $insert_user ){
$unique_user_insert = array_unique($insert_user);
//dd($unique_user_insert);
$insert_id = DB::table('users')->insertGetId($unique_user_insert);
// Now use $i requested above :
$someArray1[$i]['user_id'] = $insert_id;
DB::table( 'table_name' )->insert( $someArray1[$i] );
}

Iterating through PHP array with duplicate records and deleting one record where a value = 0

I have a MySQL query using Laravel that I convert to a PHP Array.
The rows have values similar to this:
name | override | percentage
Eclipse | 1 | 50%
Eclipse | 0 | 75%
MySQL query
select * from table
Both rows (it's many more than just 2 in reality) have the same name, but one has override set to 0 and one has it set to 1.
How can I get rid of all records in my query result (PHP array) that are duplicates (determined by the name) AND have override set to 0? I want only the records that have been overridden with a new record which I have done, but I need a way to remove the records with override = 0, given that the records are the same but have a different percentage value.
How can this be done?
Thanks.
Try following query,
SELECT * from testtable GROUP BY `name` HAVING count(`name`) = 1 OR `override` = 1;
check this sqlfiddle
If I understand your needs correctly, you need to filter out records that have duplicate name and override = 0.
If you sort your result set by name (SELECT * FROM TABLE ORDER BY name), you can use this function.
function removeDuplicatesFromArray($rows) {
$result = array();
$old_name = '';
foreach($rows as $row) {
if($row['name'] != $old_name) {
$result[] = $row;
$old_name = $row['name'];
}
elseif($row['override'] == 1) {
array_pop($result);
$result[] = $row;
}
}
return $result;
}
NOTE: Doing this in SQL will be WAYYYYYYYYY faster and use far less memory. I would only try this PHP approach if you cannot modify the SQL for some reason.
Maybe try out... hit the db twice, first time only get non-overrides, then get the overrides in second pass -- coerce your arrays to be indexed by name and array_merge them. (Uses a fair chunk of memory given the number of arrays and copies - but it's easy to understand and keeps it simple.
$initial = get_non_overridden();
$override = get_overridden();
$init_indexed = index_by_name($initial);
$over_indexed = index_by_name($override);
$desired_result = array_merge($init_indexed, $over_indexed);
Assuming your database gives you a standard rowset (array of rows, where each row is a hash of fields->values). We want something that looks like this instead:
[
'Eclipse' => [
'name' => 'Eclipse',
'override' => '0',
'percentage' => '75%'
],
'Something' => [
'name' => 'Something',
'override' => '0',
'percentage' => '20%'
],
]
So index_by_name would be:
function index_by_name($rowset) {
$result = array();
foreach ($rowset as $row) {
$result[ $row['name'] ] = $row;
}
return $result;
}
There are ways to tweak your efficiency either in memory or run time, but that's the gist of what I was thinking.
array_merge then overwrites the initial ones with the overridden ones.
NOTE: this all assumes that there is only one row where Eclipse override is 1. If you have twenty Eclipse|0 and one Eclipse|1, this will work, if you have two Eclipse|1 you'd only see one of them... and there's no way to say which one.

Elegant Efficient way of inserting into a lot of tables MySQL

I am making a survey and currently the database has 19 tables and roughly 100 columns. All of them will be inserted to as they are required fields. I am looking for an Elegant and Efficient way of inserting into that many tables and columns. So far what I have come up with is to create a multidimensional array that contains the first key as the table name and the second key as the column name with the field. Something like below:
$tableArray = array(
'ownerTable' => array(
'firstNameRow' => $firstName,
'lastNameRow' => $lastName
),
'dealerTable' => array(
'dealerNameRow' => $dealerName,
'dealerCityRow' => $dealerCity
)
);
foreach($tableArray as $row => $key) {
foreach($tableArray[$row] as $row1) {
$sql = "(INSERT INTO $tableArray[$key] ($tableArray[$row]) VALUES ($row1)";
}
}
I didn't test this code but I am thinking something along those lines would work. I think one problem I see with this is a separate INSERT for each column instead of one INSERT for each table. I can always work on writing the code to just load all the values from the array at once to solve this problem but before I start getting to carried away I want to make sure I am not making a big mistake and waste time if there is a better way to do it.
$tableArray = array(
'ownerTable' => array(
'firstNameRow' => $firstName,
'lastNameRow' => $lastName
),
'dealerTable' => array(
'dealerNameRow' => $dealerName,
'dealerCityRow' => $dealerCity
)
);
//it's for bulj query execution in single statment;
$i=1;
$sql="";
foreach($tableArray as $row => $key) {
foreach($tableArray[$row] as $row1) {
//here you can update i value as per row for execution
if($i<=25)
{
$sql = $sql + "(INSERT INTO $tableArray[$key] ($tableArray[$row]) VALUES ($row1);";
}
else
{
//execute sql statement here;
$i=0;
$sql="";
}
}
}

Php merge arrays [duplicate]

This question already has answers here:
Is there a php function like python's zip?
(14 answers)
Closed 7 months ago.
So I have these two foreach
foreach($find as $e) {
$theData[] = array('href' => $e->href, 'linkText' => $e->plaintext);
foreach($findText as $f){
$theData[] = array('description' => $f->plaintext);
}
}
So I need that the result to be something like this: $theData = array('href' => $e->href, 'linkText' => $e->plaintext,'description' => $f->plaintext);
array_merge doesn't do want I want to achive.Any help?
Try...
$i = 0;
foreach($find as $e){
$data[$i] = array('href' => $e->href, 'linkText' => $e->plaintext);
foreach($findText as $f){
$data[$i]["description"][] = $f->plaintext;
}
$i++;
}
If your arrays both have automatically created integer keys, then it's simple:
$theData = array();
for($i = 0; $i < count($e); ++$i) {
$theData[] = array(
'href' => $find[$i]->href,
'linkText' => $find[$i]->plaintext,
'description' => $findText[$i]->plaintext);
}
Note that the above code will not work correctly if $find and $findText don't have the same number of items, or if the keys don't match. Generally, making this work without more specific information will get quite messy.
The best practical advice I can give is to re-examine the code which creates $find and $findText -- it will be much easier to achieve your goal at that time.
Allow me to make the assumption that you are combining information from two queries. One option you have is to get href, linktext and description from your database all at once by joining your query.
select table_1.href,table_1.plaintext, table_2.plaintext
from table_1
where //insert your where clause, if appropriate
join table_2 on table_1.id = table_2.parent_id
where table one is your $find array and table_2 is your $findText array; and table_2.parent_id is a value matching the id from table_1. Joining the tables in this query will store all the fields from your two assumed queries into one variable.

Categories