Convert foreach php queries into SQL - php

I have two php functions that perform rather slowly since i have a large database. One makes a request for category names. The other makes a subcategory count. Below, I have tried converting to SQL to speed up queries but not sure how to work around the foreach loop, or if this is the most efficient SQL query method. Your feedback is appreciated.
The first:
function GetCatName($catid){
global $db, $dblang, $the_cats;
foreach($the_cats as $cat){
if($cat->category_id == $catid && $cat->category_lang == $dblang)
{
$x = $cat->category_name;
}
}
return $x;
}
Rewrite to SQL:
function GetCatName($catid){
global $db, $dblang;
$sql = "SELECT category_name FROM ".table_categories." where category_id = ".$catid." and category_lang = ".$dblang.";";
$x = $db->get_result($sql);
return $x;
}
The second:
function GetSubCatCount($catid){
global $db, $the_cats;
$count = 0;
foreach($the_cats as $cat){
if(isset($cat->category_parent)){
if($cat->category_parent == $catid && $cat->category__auto_id <> 0 && $cat->category_lang == $dblang)
{
$count = $count + 1;
}
}
}
return $count;
}
Rewrite to SQL:
function GetSubCatCount($catid){
global $db, $the_cats;
$count = 0;
foreach($the_cats as $cat){
if(isset($cat->category_parent)){
$sub_cateogories = $db->get_results("SELECT * FROM ".table_categories." where category_parent = ".$cat->category__auto_id." and category_order = 0 AND category__auto_id<>0;");
$count = count($sub_cateogories);
}
}
return $count;
}
Thanks

As I mentioned in the comment you need to use $catid, otherwise the query has no improvement whatsoever.
This can be done as you did it in the first case where you replaced
$cat->category_id == $catid && $cat->category_lang == $dblang
through
category_id = ".$catid." and category_lang = ".$dblang."
This would bring us to changing the where statement to
category_parent = ".$catid." and category_order = 0 AND category_auto_id<>0
without using the foreach loop of course

Related

Is there a way to update 12000+ rows from txt file in less then 2mins?

I need to update a table with more then 12000 row using php Codeigniter and a txt file.. reading the file and the foreach loop are fine but when updating line by line it takes like 30 mins, I guess the problem is I'm searching by name because I have no id in the txt file...
Here is my code:
controller:
$fn = fopen($this->upload->data('full_path'),"r");
$update = true;
while(! feof($fn) && $update) {
$pieces = explode("|", fgets($fn));
if(sizeof($pieces) == 9 && is_numeric(trim($pieces[1]))) {
$update = $this->model_products->update3s($pieces);
}
}
fclose($fn);
Model:
public function update3s($product) {
if ($product) {
$product[2] = trim(str_replace("'","''",$product[2]));
$product[1] = trim($product[1]);
$product[6] = trim($product[6]);
$product[3] = trim($product[3]);
$sql = "UPDATE products set qty = $product[3], price_vente = $product[6] where (name = '$product[2]')";
echo $sql.'<br>';
$update = $query = $this->db->query($sql);
return $update;
}
return false;
}
You can use transaction and add index for column name in database table.
$fn = fopen($this->upload->data('full_path'),"r");
$update = true;
$updatedCount = 0;
while(! feof($fn) && $update) {
$pieces = explode("|", fgets($fn));
if(sizeof($pieces) == 9 && is_numeric(trim($pieces[1]))) {
if ($updatedCount == 0) {
$databaseInstance->beginTransaction();
}
$update = $this->model_products->update3s($pieces);
++$updatedCount;
if ($updatedCount > 500) { //in one transaction update 500 rows
$databaseInstance->commit();
$updatedCount = 0;
}
}
}
if ($updatedCount > 0) { // if we have not commited transaction
$databaseInstance->commit();
}
fclose($fn);
Some tips
Add index to field name
Use prepared statements
Disable the MySQL forgeign key check Read more
writing sql function can do that even in much lesser time .
using feature like :
REPLACE()
cursors
SPLIT_STRING(custom)
in a mysql user defined function
CREATE FUNCTION update3s(hole_file_content LONGTEXT) RETURNS Boolean
BEGIN
-----Your implementation(same logic in sql ) ------
END
then coll it just by if it is CI 3
$this->db->call_function('update3s', file_get_contents($this->upload->data('full_path')));
else
$this->db->query("select update3s(".file_get_contents($this->upload->data('full_path')).")");

PHP - Error when trying to use ceiling function on data retrieved from database

Below is my PHP code. I'm tying to retrieve values from a database and round them to the nearest 10 (upwards only). All the values in the database in this column are integers.
<?PHP
#$Teach_ID = $_POST['txtteachID'];
#$Class_ID = $_POST['txtclass'];
#$BookingDate = $_POST['txtbookingdate'];
#$BookingPeriod = $_POST['txtperiod'];
require_once('../BookingSystem/DBconnect.php');
$capacity = 'SELECT ClassSize FROM classes WHERE ClassID = 1';
$result = $dbh->query($capacity);
$result = (int)$result;
function ceiling($number, $significance = 1)
{
return ( is_numeric($number) && is_numeric($significance) ) ? (ceil($number/$significance)*$significance) : false;
}
}
if ($result->num_rows > 0) {
echo ceiling($result, 10);
}
?>
Error Description
Am I missing something obvious?
You need to loop through your $result variable, which is a mysqli_result object, to get its different entries.
Use mysqli_fetch_assoc to get the values, which will end in something like this :
$capacity = 'SELECT ClassSize FROM classes WHERE ClassID = 1';
$result = $dbh->query($capacity);
function ceiling($number, $significance = 1)
{
return ( is_numeric($number) && is_numeric($significance) ) ? (ceil($number/$significance)*$significance) : false;
}
}
while ($row = $result->fetch_assoc()) {
// if ($result->num_rows > 0) { /* I think this condition is not needed anymore */
$value = intval($row['ClassSize'], 10); // will convert the string from database to an int in base 10
echo ceiling($value, 10); /* I suppose you wanted to use the ClassSize key since it's the one you query */
// }
}
You can't do this $result = (int)$result;. You have to irritate over each row and then extract the data.

function returning only once, why?

During my coding I really got stuck into this problem.
I ran a foreach loop and for every item I had to get a certain value from a function.
But I got only one returned. I could not figure out what was happening. I hope you guys surely will.
Below is the short version of my program.
Database structure is given at last.
<?php
function opendb() {
mysql_connect("localhost", "root", "root");
mysql_select_db("something_db");
}
function sql_query($sql) {
$datas = array();
if ($res = mysql_query($sql)) {
$x = 0;
while ( $data = mysql_fetch_assoc($res) ) {
$datas[$x] = $data;
$x += 1;
}
}
return $datas;
}
function get_parent_id($table, $parent, $cid) {
// cid=>child id
$sql = "SELECT * FROM $table WHERE id=$cid";
$datas = sql_query($sql);
$pid = $datas[0]['parent'];
$p_id = $datas[0]['id'];
if ($pid != 0) {
get_parent_id($table, $parent, $pid);
} else {
return $p_id;
}
}
opendb();
$datas_pkg = sql_query("SELECT * FROM tbl_packages WHERE 1");
foreach ( $datas_pkg as $data_pkg ) {
echo $data_pkg['destination_id'] . '-->';
echo $parent_id = get_parent_id('tbl_destinations', 'parent', $data_pkg['destination_id']);
echo '<br/>';
}
?>
Database structure..
tbl_destinations
+--------+-------------------------+-----------+
| id(int)|destination_name(Varchar)|parent(int)|
+--------+-------------------------+-----------+
tbl_packages
+-------+---------------------+-------------------+
|id(int)|package_name(varchar)|destination_id(int)|
+-------+---------------------+-------------------+
If I did not clear my question please let me know so that I can help you to help me.
if($pid!=0)
{
get_parent_id($table,$parent,$pid);
}
You call the function, but never use its value.

What is wrong with my function?

Here is my code for the function
function multiple_delete($checkbox, $table = 0, $url = 0, $picture1 = 0, $picture2 = 0, $picture3 = 0){
echo $count = count($checkbox);
for( $j=0;$j<$count;$j++)
{
$delete_id = $checkbox[$j];
$query = "SELECT * FROM $table WHERE id = '$delete_id'";
$result = mysql_query($query);
$row = mysql_fetch_array($result);
if( $picture1 !== 0 && $picture2 !== 0 && $picture3 !== 0)
{
$pic_1 = $picture1;
$pic_2 = $picture2;
$pic_3 = $picture3;
unlink($pic_1);
unlink($pic_2);
unlink($pic_3);
continue;
}
if( $picture1 !== 0 && $picture2 !== 0 && $picture3 == 0 )
{
$pic_1 = $picture1;
$pic_2 = $picture2;
unlink($pic_1);
unlink($pic_2);
continue;
}
}
for($i=0;$i<$count;$i++) {
$del_id = $checkbox[$i];
$sql = "DELETE FROM $table WHERE id='$del_id'";
$result_delete_data = mysql_query($sql);
}
alert('Deleted Successfully');
redirect_url($url);
return true;
}
My Problem is when i call the function using the following code.
#multiple_delete($_POST['checkbox'], 'news', 'news.php', '$row[\'pic_title\']', '$row[\'pic_brief\']', '$row[\'pic_detail\']');
the three array variables $row['pic_title'], $row['pic_brief'], $row['pic_detail'] , does not parse as the value in the function in first for loop, instead it just print the string and hence is not able to fetch the value stored in the database. for example
in the first if condition i have defined 3 variables,
$pic_1 = $picture1;
$pic_2 = $picture2;
$pic_3 = $picture3;
$picture1, $picture2, and $picture3 holds the value that i declared in the function , now when i do something like this echo $pic_1 = $picture1; it prints $row['pic_title'] the exact value which i declared in the function instead of parsing the value which is actually upload/news/title/pic_title1.jpg i tried testing it like this, instead of declaring the value in the defined function i actually just changed the value of the three variables to
$pic_1 = $row['pic_title'];
$pic_2 = $row['pic_brief'];
$pic_3 = $row['pic_detail'];
this works very fine without any problem. why is that variable $picture1 which holds the value $row['pic_title']; refuses to parse it and force it to just print the string while if i change it manually it works? where i am going wrong?
apart from the last three parameters i dont have any problem parsing the first three parameters it works perfectly fine i have tested it in many ways. the only problem i am facing is of the last three parameters
Edit : i tried double quotes, single quotes, and single quotes with double quote with the combination of concatenation operator. without quotes. nothing works.
P.S : thanks in advance
Try this:
function multiple_delete($checkbox, $table, $url, $picture1, $picture2, $picture3){
echo $count = count($checkbox);
for($j=0; $j<$count; $j++)
{
$delete_id = $checkbox[$j];
$query = "SELECT * FROM $table WHERE id = '$delete_id'";
$result = mysql_query($query);
$row = mysql_fetch_array($result);
$pic1 = $row[$picture1];
$pic2 = $row[$picture2];
$pic3 = $row[$picture3];
if(!empty($pic1) && !empty($pic2) && !empty($pic3))
{
unlink($pic1);
unlink($pic2);
unlink($pic3);
}
else if(!empty($pic1) && !empty($pic2))
{
unlink($pic1);
unlink($pic2);
}
$sql = "DELETE FROM $table WHERE id='$delete_id'";
$result_delete_data = mysql_query($sql);
}
// this is javascript, not php
// alert('Deleted Successfully');
redirect_url($url);
return true;
}
Call the function like this:
multiple_delete($_POST['checkbox_name'], 'table_name', 'redirect_url', 'column_name_pic_1', 'column_name_pic_2', 'column_name_pic_3');
get rid of the apostrophes around your variable names in the function call, ie try
, $row[\'pic_title\'],
instead of
, '$row[\'pic_title\']',
I got the solution for this problem. in case it can benefit anyone here is the link to the solution.
How do i parse the the value from a string in the function call?

Printing the Categories and Sub Categories Alone

function build_list($id=0,$collapsed="") //return an array with the categories ordered by position
{
$RootPos = "";
$this->c_list = array();
if($id != 0){
$this_category = $this->fetch($id);
$positions = explode(">",$this_category['position']);
$RootPos = $positions[0];
}
// lets fetch the root categories
$sql = "SELECT *
FROM ".$this->table_name."
WHERE position RLIKE '^([0-9]+>){1,1}$' AND c_group = '".$this->Group."'
ORDER BY c_name";
$res = mysql_query($sql) or die(trigger_error("<br><storng><u>MySQL Error:</u></strong><br>".mysql_error()."<br><br><storng><u>Query Used:</u></strong><br>".$sql."<br><br><storng><u>Info:</u></strong><br>",E_USER_ERROR));
while($root = mysql_fetch_array($res)){
$root["prefix"] = $this->get_prefix($root['position']);
$this->c_list[$root['id']] = $root;
if($RootPos == $root['id'] AND $id != 0 AND $collapsed != ""){
$this->list_by_id($id);
continue;
}else{
// lets check if there is sub-categories
if($collapsed == "" AND $id==0){
$has_children = $this->has_children($root['position']);
if($has_children == TRUE) $this->get_children($root['position'],0);
}}}
return $this->c_list;
}
// He is the Author of the code...
Categories Class
Author: Shadi Ali
Now I want to just return the Categories and Sub Categories from the above code.
function browse() {
$categories = new categories;
$categories_list = $categories->build_list();
foreach($categories_list as $c)
{
return $c->$id;
}
}
The above code is not working.... can anyone help me out.
Here are two problems with the browse() function:
The return statement is inside the foreach loop. The statement will return one value for one of the items in the $categories-list (at most), and not continue to loop over the rest of the $categories-list.
The $id variable is never declared or initialised in return $c->$id, perhaps you meant to use $c['id'] or $c->id

Categories