Codeigniter database backup - Insert multiple rows without repeating “INSERT INTO” - mysql

I'm trying out to find a way to backup my database using Codeigniter "Database Utility" but without repeating “INSERT INTO”, I mean everything works perfectly, but when we see the generated sql file we see something like this:
INSERT INTO Membership (ID, FirstName, LastName, DOB)
VALUES (1, 'John', 'Smith', '5/5/1960')
INSERT INTO Membership (ID, FirstName, LastName, DOB)
VALUES (2, 'Hello", 'World", '4/9/1975')
INSERT INTO Account(ID, Type, Effective_Date, Status)
VALUES (1, 'Gold', GetDate(), 'Active')
INSERT INTO Account(ID, Type, Effective_Date, Status)
VALUES (2, 'Platinum', GetDate(), 'Inactive')
INSERT INTO Participant(ID, Code, Type)
VALUES (1, 002, 'A')
INSERT INTO Participant(ID, Code, Type)
VALUES (2, 002, 'A')
The which is so slow whenever we import in another database. I want to get something like this:
INSERT INTO #temp_table (1, 'John', 'Smith, '5/5/1960', 'Gold', 'Active', '002', 'A')
.
.
.
.
so on
using only one INSERT INTO, is there any way to achieve this? Thanks.

You can make use of CodeIgniter insert_batch() function
Follow this link here to see how it works:

Create a multi-dimensional array with field and values like this, and use codeigniter inset_batch() function to insert all these in a single query.
$data = array(
array(
'ID' => 1,
'FirstName' => 'John',
'LastName' => 'Doe',
'DOB' => '5/5/1960'
),
array(
'ID' => 2,
'FirstName' => 'John',
'LastName' => 'Smith',
'DOB' => '5/5/1960'
)
);
$this->db->insert_batch('temp_table', $data);

I understand your problem, Database Utility is quite slow also, due to string concatenation, if passthru() is enabled on your server, then mysqldump can be used, here is working code, which will export current database.
public function backup_current_db()
{
$db_user=$this->db->username;
$password=$this->db->password;
$db=$this->db->database;
$filename = $db . "-" . date("Y-m-d_H-i-s") . ".sql";
$mime = "application/octet-stream";
header( "Content-Type: " . $mime );
header( 'Content-Disposition: attachment; filename="' . $filename . '"' );
$cmd = "mysqldump -u '$db_user' --password='$password' --no-create-info --complete-insert '$db' ";
passthru( $cmd );
die();
}

Related

How to check if record was changed on db after inserting data?

I insert some data from a db.table1 to db.table2 with a cronjob which runs every minutes. But I need to check if any record has changed after data is inserted on table2 because I get some wrong data on this table when data is inserted.
this is crontab function
$data = DB::connection('mysql2')
->table('students')
->where('status', '=', 'Y')
->get();
foreach ($data as $key => $aStudent) {
// Check if student_id duplicated
$existing_data_in = DB::table('student')
->where("student_id", $aStudent->student_id)
->first();
if (! $existing_data_in) {
DB::connection('mysql')->table('student')->insert([
"first_name" =>$aStudent->first_name,
"last_name" =>$aStudent->last_name,
"age" =>$aStudent->age,
"student_id" =>$aStudent->student_id,
"created_at" =>$aStudent->created_at
]);
}
}
Log::info('Success, Data Updated');
Or maybe should I run cronjob rarely? My problem is when some record on table1 are filed with data and when this record goes to table2 are empty on table2. If I check same student_id on table1 is okay but on table2 are saved empty
i have loged my query on cronjob and this is what i get in case i find an empty filed on table 2. So last name on table 1 in this case is filled with really last name but on table 2 is inserted as empty and this is query (what hapend)
[2022-01-19 14:16:17] local.INFO: select `student_id` `first_name`, `last_name`, `age`, `created_at` from `students` where `student_id` = ? limit 1 [421]
// this comes from query where i check for dublicated lines i think
[2022-01-19 14:16:17] local.INFO: select * from `student` where `student_id` = ? limit 1 [421]
[2022-01-19 14:16:17] local.INFO: insert into `student`
(`student_id`, `first_name`, `last_name`, `age`, `created_at`) values
(?, ?, ?, ?, ?)
["421","name","","38","2022-01-19 14:13:35"]
If the tables contain created_at and updated_at columns, you can tell if a record has been updated by comparing the two columns.
->whereRaw('created_at != updated_at')->get();
You could wrap everything in a transaction to make sure it works as it should.
$data = DB::connection('mysql2')
->table('students')
->where('status', '=', 'Y')
->get();
$dataToInsert = $data->map(function ($item) {
return [
'first_name' => $item->first_name,
'last_name' => $item->last_name,
'age' => $item->age,
'student_id' => $item->student_id,
'created_at' => $item->created_at
];
})->all();
$columnsToCheck = ['student_id'];
$columnsToUpdate = [];
$conn = DB::connection('mysql');
$conn->beginTransaction();
try {
$conn->table('student')->upsert($dataToInsert, $columnsToCheck, $columnsToUpdate);
$conn->commit();
Log::info('Success');
} catch (\Exception $e) {
$conn->rollBack();
Log::error($e);
}
I'm using upsert. You can read more about it here.
https://laravel.com/docs/8.x/queries#upserts

Entering an array into my database using mySQL

I know I am doing this completely wrong, but current I have:
$genre0 = addslashes(strip_tags($movieInfo[genres][0][name]));
$genreid0 = addslashes(strip_tags($movieInfo[genres][0][id]));
...
$genre4 = addslashes(strip_tags($movieInfo[genres][4][name]));
$genreid4 = addslashes(strip_tags($movieInfo[genres][4][id]));
Then
mysql_query($query = "INSERT INTO tblMovies (movie_id, genre_id, genre_name) VALUES ($movie_id , $genreid0, $genre0");
...
mysql_query($query = "INSERT INTO tblMovies (movie_id, genre_id, genre_name) VALUES ($movie_id , $genreid4, $genre4");
I know this is extremely repetitive, but it is the only way I can figure out that works. I have tried a ton of for each statements to no avail. I have tried following this one insert multiple rows via a php array into mysql and a few others, but cannot seem to figure it out.
This is embedded in a SELECT/WHILE statement that runs through a list of movies...
Any tips or suggestions would be greatly appreciated!
Thanks!
You can use prepared statements for handy execution of your query:
$stmt = $dbh->prepare("INSERT INTO tblMovies (movie_id, genre_id, genre_name)
VALUES (:movie_id , :genreid, :genre")");
$stmt->bindParam(':movie_id ', $movie_id);
$stmt->bindParam(':genreid', $genreid);
$stmt->bindParam(':genre', $genre);
for($i=0; $i < count($movieInfo['genres']); $i++){
$movie_id = i;
$genreid = addslashes(strip_tags($movieInfo['genres'][i]['id']));
$genre = addslashes(strip_tags($movieInfo['genres'][i]['name']));
$stmt->execute();
}
If you insist on using mysql_XXX:
foreach ($movieInfo['genres'] as $genre) {
$genre = mysql_real_escape_string(strip_tags($genre['name']));
$genreid = mysql_real_escape_string(strip_tags($genre['id']));
mysql_query("INSERT INTO tblMovies (movie_id, genre_id, genre_name) VALUES ($movie_id , '$genreid', '$genre'");
}
I would insist that insert multiple records in database by firing single query instead of firing seperate query for each record.
E.g.:
INSERT INTO tblMovies
(genre_id, genre_name)
VALUES
('Name 1', 'Value 1'),
('Name 2', 'Value 2'),
('Name 3', 'Value 3'),
('Name 4', 'Value 4');
//Prepare the entire query using foreach and then fire single query.
foreach ($movieInfo['genres'] as $genre) {
$genre = mysql_real_escape_string(strip_tags($genre['name']));
$genreid = mysql_real_escape_string(strip_tags($genre['id']));
$parts[] = "('.$genreid.', '.$genre.')";
}
$str = implode("," $parts);
$query = "INSERT INTO tblMovies (genre_id, genre_name) VALUES ".$str.";";
mysql_query($query) or die(mysql_error());
Note: I have used mysql as you have mentioned in question but it is recommended to switch to mysqli or PDO. Also, from the question you have mentioned, I assume that $movie_id is auto-increment.

Insert multiple values in one column mysql?

I have a table of checkboxes and values, if a user selects a checkbox they select the value of the id in an array called checkedHW for simplicity sake this is what code looks like:
$ids = implode(',',arrayofids);
$sql = "insert into table(id, type) values($ids,type);
$db->query($sql);
echo query for testing:
"insert into table('id1,id2','type')
I figured that if I loop through this query I could hypothetically do this:
"insert into table('id1','type');"
"insert into table('id2','type');"
but I'm not exactly quite sure how to do, any help would be wonderful :)
I actually solved it using:
for($i=0;$i<count(arrayofids); $i++){
$sql = "insert into table(id,type) values(array[$i], 'type'";
$db->query($sql);}
I hope that helps someone and thank you guys for the help!
You could do something like this:
$base = 'INSERT INTO table (id, type) VALUES (';
$array = array(1, 2, 3, 4);
$values = implode(", 'type'), (", $array);
$query = $base . $values . ", 'type')";
$db->query($query);
This is what would be getting submitted:
INSERT INTO table (id, type) VALUES (1, 'type'), (2, 'type'), (3, 'type'), (4, 'type')
Both query are completely different
insert into table('id1,id2','type') will insert single row
id1,id2 | type
whereas
insert into table('id1','type');"
insert into table('id2','type');"
will insert two rows
id1 | type
id2 | type
so if your id column is int type then you cant run first query
If you have a series of checkboxes, and wanting to insert the values into your table, you could loop through them like this:
<?php
$values = array();
foreach ($_POST['field_name'] as $i => $value) {
$values[] = sprintf('(%d)', $value);
}
$values = implode(',', $values);
$sql = "INSERT INTO `table_name` (`column_name`) VALUES $values";
This will give you a SQL query similar to:
INSERT INTO `table_name` (`column_name`) VALUES (1),(2),(3),(4)
Hope this help.

Codeigniter batch insert performance

Does $this->db->insert_batch(); insert with 1 table connection or does it insert each row separately incurring overhead of opening connections?
From the documentation of code igniter insert_batch do this kind of things
$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')
So it would produce only one query with all the values, normally this way faster then doing separate inserts.
To answer your question: It uses one connection.
Actually #RageZ answer based on document is not always correct. Because it's totally based on the number of items you want to insert. When looking at codeigniter insert_batch() code, you can see that they slice batch inserts into 100 items.
// Batch this baby (Around line number 1077 in codeigniter 2.x)
for ($i = 0, $total = count($this->ar_set); $i < $total; $i = $i + 100)
{
$sql = $this->_insert_batch($this->_protect_identifiers($table, TRUE, NULL, FALSE), $this->ar_keys, array_slice($this->ar_set, $i, 100));
//echo $sql;
$this->query($sql);
}
It means that your values will be slice to 100s inserts and if you uncomment the echo $sql part you can see what it's look like when you use insert batch for 101 items. So based on your connection preferences there can be more than one connection needed for inserting in db.

MySQL query fails on integrity constraint violation

This query keeps failing with
Integrity constraint violation: 1048 Column 'login_name' cannot be null
My insert statement is...
$insertUserQuery = 'INSERT INTO `users` (
`login_name`,
`password`,
`first_name`,
`last_name`,
`company_name`,
`company_address`,
`country`,
`email`,
`phone_number`,
`agency_type`,
`sold_before`,
`authorised`,
`current_module`
)
VALUES (
:login_name, :login_password, :first_name, :last_name, :company_name, :company_address, :country, :email, :phone_number, :agency_type, :sold_before, 0, 0);';
$bindings = array(':login_name' => $loginName,
':login_password' => sha1($password . Config::PASSWORD_SALT),
':first_name' => $firstName,
':last_name' => $lastName,
':company_name' => $companyName,
':company_address' => $companyAddress,
':country' => $country,
':email' => $emailAddress,
':phone_number' => $phone,
':agency_type' => null,
':sold_before' => null
);
print_r($bindings);
Db::query($insertUserQuery, $bindings);
My database class can be found at another question. The print_r() tells me that the array definitely has a value.
May it have something to do with me using the word 'password' which is also a MySQL function?
Does PDO support prepared statements with INSERT in the same fashion as it does with SELECT?
Do I need to quote around the values, example ':login_name'?
PDO::query doesn't support prepared statement syntax does it? Give PDO::prepare and PDOStatement::execute a read. You probably want something like:
$insertUserQuery = 'INSERT INTO `users` (`login_name`, ...) ' .
'VALUES (:login_name, ...);';
$bindings = array(':login_name' => $loginName, ...);
$stmt = Db::prepare($insertUserQuery);
$stmt->execute($bindings);
You can also call $stmt->bindValue() instead of building an array of bindings. I think that explicitly binding each value is a little nicer since you can verify the types right there.
EDIT: sorry jcinacio, I didn't see that your comment was almost identical until after I posted.