CodeIgniter 3 MySQL query randomly works intermittently - php

I made a function in a CI model that first queries for the table to get its fields(because these fields will change dynamically over time,so I can't hard code a list of field names),and then when it gets the results of the first query, and builds a fields name list,it queries the table again to get the values belonging to one row or record.It then stores the second query result in an array,which is passed back to the controller.Here is the complete function that performs these steps:
public function getAssetFeatures($as_id)
{
$data = array();
//this sql query gets the field names from the table I want to query.
$sql = "SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = '".DATABASE."' AND TABLE_NAME = 'as_features';";
$query = $this->db->query($sql);
$count = 0;
foreach($query->result_array() as $k)
{
foreach($k as $kk=>$v)
{
if( $v != "as_features_id" &&
$v != "as_id" &&
$v != "cid" &&
$v != "lot_size" )
{
$features_array[$count] = $v;
$count++;
}
}
}
$features_string = implode(",",$features_array);
//I got the field names, put them into an array, then concatenated them into a string, which I will use for the fields in the next query:
$sql = "SELECT $features_string FROM as_features WHERE as_id='$as_id'";
$query = $this->db->query($sql);
//mandatory rooms/features:
foreach($query->result() as $row)
{
foreach($row as $k=>$v)
{
$data["$k"] = $v; //build an associative array with the values of each field for the one row I am querying
}
}
return $data; // return the associative array.
}
At first I thought something was broken in my table or view,but as I kept repeating the same call to the model function by refreshing the page and entering the exact same values,I noticed that sometimes the code worked,and I wouldn't get the errors "undefined index".
So I outputted the results of the array with this code:
echo "<pre>";
print_r($asset['features']);
echo "</pre>";
...and the expected output, which only performs successfully sometimes, but not all the time, for the exact same operation using the exact same parameters, looks like this:
Array
(
[kitchen] => 1
[liv_area] => 0
[dining] => 1
[family] => 0
[bed] => 0
[bath] => 1
[half_bath] => 0
[parking] => 0
[car_storage] => 0
[pool] => 0
[miscellaneous] => 0
)
When the query returns a result set and then a populated array,my form works and looks normal.but,most of the time the query fails,and I get what looks like this:

The issue is with the following snippet of code:
foreach($query->result() as $row)
{
foreach($row as $k=>$v)
{
$data["$k"] = $v; //build an associative array with the values of each field for the one row I am querying
}
}
The way it works is that for every result which is returned it will overwrite $data with the relevant keys. However, because the $query->result() will return the row you want, then return false, the array essentially ends up being:
$data[] = false; i.e., set the whole array to false/empty.
If you change the loop to be, the code inside the loop won't be executed for the false value of $query->result():
while ($row = $query->result())
{
// your code
}
It's worth noting that if you're intending to return more that one row from this, it won't work as it will just overwrite the existing values.

Ok, the problem was my code, not the query. I was passing an encrypted as_id, but neglected to unencrypt it before constructing the select query. That's why it would work sometimes, and not others. For some reason MySQL allowed the encrypted as_id to match existing as_id of INT type. After performing the decrypt, the query results became predictable. This is something I wouldn't expect SO members to have divined. Thanks.
public function getAssetFeatures($as_id)
{
$as_id = $this->utilityclass->decryption9($as_id); // <- I had this commented out. In fact, I removed the line from my example code in the original post, because I didn't think it was important to the question. Not only was it important, it was the problem!
$data = array();
$sql = "SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = '".DATABASE."' AND TABLE_NAME = 'as_features';";
$query = $this->db->query($sql);

Related

Pushing values and keys to an multidimensional array from the database inside a foreach loop without repetitions

I'm trying to combine two tables from a database, and based on my first one, I want to retrieve some value from the other one, and add them to an array.
Here's my problem:
My first database looks like that:
FIRST TABLE:
id, credit_type, association_name, address, city, province, postal_code, country, cycle_type, cycle_begin, cycle_months
My second database instead looks like that:
SECOND TABLE:
id, association_id, designation_name
The id in my first table matches the association_id in my second table so I don't need an INNER JOIN.
My approach is the following:
<?php
public function my_function()
{
$sql = ee()->db->select('*')->from('first_table')->get();
$data['database'] = [];
if ($sql->num_rows() > 0)
{
foreach($sql->result_array() as $row)
{
$id[] = $row['id'];
$data['database'][] = $row;
}
}
foreach ($data['database'] as $key => $value) {
$association_query = ee()->db->query("SELECT * FROM second_table WHERE id = $id");
foreach($association_query->result_array() as $row_two)
{
if ($association_query->num_rows() > 0)
{
$data['database'][$key]['associations'][] = $row_two['designation_name'];
}
}
}
return ee()->load->view('index', $data, true);
}
?>
The sintax ee()->db->select('*') is a prepared statment from expression engine and it's equal to SELECT * FROM first_table (sanitaized).
So as you can see, I try to pass the value $id, which is an array, to my query. The thing is that as soon as I push the value like that $id[] = $row['id'] I create a nice array, but when I loop through my foreach loop, it multiplies my array in many other arrays so I'm not able to run my query, even if I'm technically in a foreach loop.
Plus, as soon as I try to push the result of my query in my array, let's say changing the id in a static id for instance id=3, I obtain a really weird result, like so many arrays repeated with 1 value, 2 value, 3 value and so on, when I'd like to push my key 'association' only where it is presented in the other table.
If you won't do it on SQL, at least don't execute the second query so many times.
<?php
public function my_function()
{
$assocs = array();
$data = array('database' => array());
$association_query = ee()->db->query("SELECT * FROM second_table");
if ($association_query->num_rows() > 0) {
foreach($association_query->result_array() as $row) {
$assocs[$row['association_id'][] = $row['designation_name'];
}
}
$sql = ee()->db->select('*')->from('first_table')->get();
if ($sql->num_rows() > 0) {
foreach($sql->result_array() as $row) {
$id_check = $row['id'];
if (isset($assocs[$id_check])) {
$row ['associations'] = $assocs[$id_check] ;
}
$data['database'][] = $row;
}
}
return ee()->load->view('index', $data, true);
}
?>
Regards

MySQLi result null second time I use it

I'm trying to run a second query using the results of my first query to set a flag for all the rows that were just retrieved. The first time I use my result to output JSON it works fine, but the second time I try to call fetch_assoc() from it, the array comes back NULL.
$result = API::$connection->query($query);
if (!mysqli_error(API::$connection))
{
API::setHeader(200);
// return json encoded results
/// This works just fine, outputs JSON
echo JSONizer::jsonEncodeSqlResultWithKeys( $result, array (
'pId',
'sender',
'receiver',
'content',
'notified',
'opened',
'time' ) );
// initial update query
$query = 'UPDATE messages
SET received=1
WHERE ';
// start by cycling through each pId received and tack each onto query
$counter = 0;
// this never runs because the associated array returns NULL now
while ($row = mysqli_fetch_assoc($result));
{
$pId = $row['pId'];
// concat query
$query .= 'pId='.$pId;
// if there's still more to go, tack on OR
if ($counter++ != count($result))
{
$query .= ' OR';
}
else
{
$query .= ';';
}
}
I've tried object and procedural style on calling fetch_assoc, did not make a difference. I tried copying the result into another variable to use, but that was NULL as well. Why would this only work once, but not a second time.

i was wondering how to handle a MySQL request in php as an Object?

I was wondering how I can handle a mysql request in php precisely as an object.
Ex:
//supposing...
$beginning=$_GET['start'];//value equal to 3
$ending=$_GET['end'];//value equal to 17
$conn=new mysqli("localhost","user","password","databasename");
$query=$conn->query("select name, favoriteFood, weight, from tablename");
1- Supposing that tablename has 23 rows, how to printing only 14 rows, beginning for example by 3rd row and ending in 17th row, as following?
Ex:
//supposing... It, I guess, should result in error but is a sketch of my ideia
for($i=$beginning,$colsCol=$query->fetch_array(MYSQLI_ASSOC); $i<$ending; $i++)
printf("%s %s %s<\br>",$colsCol['name'][$i],$colsCol['favoriteFood'][$i],$colsCol['weight'][$i]);
2 - And later, how to order the resulted rows with $query variable?
P.S.: I know that to get results ordered, I could user order by columname, but in this case I would like to order the resulted rows after query been done.
If you want to sort later, after the query's done, then you'd need to store the results in a PHP data structure and do the sorting there. Or re-run the query with new sorting options.
As for fetching only certain rows, it'd be far more efficient to retrieve only the rows you want. Otherwise (for large result sets) you're forcing a lot of data to be pulled off disk, sent over the wire, etc... only to get thrown away. Rather wasteful.
However, if you insist on doing things this way:
$row = 0; $data = array();
while($row = $query->fetch_array(MYSQLI_ASSOC)) {
$row++;
if (($row < 3) || ($row > 17)) {
continue;
}
$data[] = $row;
}
for 2D array you can use it.
function asort2d($records, $field, $reverse=false) {
// Sort an array of arrays with text keys, like a 2d array from a table query:
$hash = array();
foreach($records as $key => $record) {
$hash[$record[$field].$key] = $record;
}
($reverse)? krsort($hash) : ksort($hash);
$records = array();
foreach($hash as $record) {
$records []= $record;
}
return $records;
} // end function asort2d
Use SQL for SQL-tasks:
"how to printing only 14 rows, begging for example by 3rd row and ending in 17th row"
$stmt = $database->prepare('SELECT `name`, `favoriteFood`, `weight` FROM `tablename` LIMIT :from, :count');
$stmt->bindValue(':from', (int)$_GET['start'] - 1);
$stmt->bindValue(':count', (int)$_GET['end'] - (int)$_GET['start']);

Working with arrays in Kohana, Blank page?

tl;dr - Pushing an array (by $array[] or $array[$id] is not working in Kohana 3, it gives a blank white page.
I'm using Kohana (3), it's my first experience with MVC and it's been great so far; however, I'm working with a database and encountered a weird problem that I was hoping someone could shed some light on:
My workflow is like this, to give you an idea of my problems surrounding:
$sql = "SELECT table1.row1, max(table2.row1) as `maxAwesome` FROM table1, table2 WHERE table1.id=table2.table1id GROUP BY table1.id";
$table1Results = DB::query(Database::SELECT, $sql)->execute();
$masterArray = array();
foreach ($table1Results as $result1)
{
$sql = "SELECT * FROM table2 WHERE table2id='" . $result1['id'] . "' AND column > 21";
$table2Results = DB::query(Database::SELECT, $sql)->execute();
$subArray = array();
foreach ($table2Results as $result2)
{
$subArray[$result1['id']] = $result2;
// Even had just $subArray[] = array("whatever");
}
$masterArray[] = array("table1Data" => array(), "table2Data"=> $subArray);
}
I do a query where I run a couple max/min functions then do a query within the foreach doing another select to build a master array of data formatted the way I want it and all the SQL etc works fine and dandy; however, the problem arises when I'm pushing the array.
It seems whenever I push the array by doing either $array[] = array("data"); or by specifying the key $array[$id] = array("data"); Kohana gives me a straight blank page, no error, no output etc.
Sometimes I get a Kohana error indicating the key does not exist (duh, I'm creating it) but for the most part the output is straight white.
Why is this happening? Am I going about it wrong?
Thanks in advance.
Clarity edit:
My SQL blunders aside, the issue lies in the building of the secondary array, for example:
$queryStores = "SELECT stores.store_id, stores.title, max(product.discount) as `max_discount`, min(product.discount) as `min_discount`
FROM stores, products
WHERE products.store=stores.store_id
GROUP BY products.store";
$stores = DB::Query(Database::SELECT, $queryStores)->execute();
$formattedStores = array();
if (count($stores))
{
foreach ($stores as $store)
{
$formattedStores[$store['store_id']] = array(
"title" => $store['title'],
);
// Same result if just doing $formattedStores[] = array();
// Problem goes away should I do:
// $formattedStores = array("This works");
//
}
}
echo "<pre>";
print_r($formattedStores);
echo "</pre>";
That does not print an array, it simply gives a blank page; however, if i change it to just re-set the $formattedStores array to something I get an output. What is it about pushing the array that's causing a problem, perhaps a Kohana bug?
Thanks
Your code should be like:-
$sql = "SELECT table1.id, table1.row1, max(table2.row1) as `maxAwesome`
FROM table1, table2
WHERE table1.id = table2.table1id
GROUP BY table1.id";
$table1Results = DB::query(Database::SELECT, $sql)->execute();
$masterArray = array();
if (count($table1Results))
{
foreach ($table1Results as $result1)
{
$sqlInner = "SELECT * FROM table2
WHERE table2id = '" . $result1['id'] . "'
AND column > 21";
$table2Results = DB::query(Database::SELECT, $sqlInner)->execute();
$subArray = array();
if (count($table2Results))
{
foreach ($table2Results as $result2)
{
$subArray[$result1['id']] = $result2;
// Even had just $subArray[] = array("whatever");
}
}
$masterArray[] = array("table1Data" => array(), "table2Data"=> $subArray);
}
}
Some valuable coding standards & miss-ups:-
You have got the "id" field (w.r.t. the "table1" DB table) missing from the first SQL.
The second SQL should be better written using another variable naming, so as to keep it separate from the first one. Hence the second variable is named as "$sqlInner".
It's always better to check for any existence of array elements in an array variable, so I have used the simple checks using the "if" statement.
Hope it helps.
I've determined this to be memory related.

MultiDimensional Arrays

In Codeigniter, I have the following model
function get_item_history($id)
{
//from metadata_history get item_id and corresponding metadata
$this->db->from('metadata_history')->where(array('id'=>$id, 'current_revision'=> "TRUE"));
$query = $this->db->get();
$result = $query->result_array(); //store this in an array
// loop through the array
foreach( $result as $key => $row )
{
$array = array('item_id'=>$row['item_id'], 'current_revision'=> "TRUE");
$this->db->from('history')->where($array);
$query = $this->db->get();
$row['items'] = $query->result_array(); //
$result[$key] = $row;
}
return $result;
}
The problem is that this results in multiple queries to the SQL table increasing the execution time significantly (pagination is not an option)
I want to be able to pass the first query results to the second query as an array, so that I would have only a single go at the database, then rebuild an array from the results.
How should I rewrite this code (the second part)? Will it be faster (I suppose so)?
EDIT
Rebuilding the array from the results is what is flummoxing me.
http://www.phpbuilder.com/board/showthread.php?t=10373847
this is what I probably want, but am failing the jump
You can use inner query here. It is ideal situation for that -
function get_item_history($id)
{
// Here the above requirement can be achieved in a single query.
$sql = "select * from history h
where h.item_id IN (select item_id from metadata_history mh where mh.id = $id
AND mh.current_revision = TRUE) AND h.current_revision = TRUE";
$result = $this->db->query($sql);
//Return whichever column of result you want to return or process result if you want.
$result;
}
You should use JOINs to do this. It'll offload the execution of the query to the server. I can't give you too much more detail without knowing how your database is structured, but check out the docs on JOINs:
http://dev.mysql.com/doc/refman/5.0/en/join.html
http://www.webdesign.org/web-programming/php/mysql-join-tutorial.14876.html
http://www.keithjbrown.co.uk/vworks/mysql/mysql_p5.php
Another option would be to do your wheres in the loop and move the query executation outside of the foreach:
// loop through the array
foreach( $result as $key => $row )
{
$array = array('item_id'=>$row['item_id'], 'current_revision'=> "TRUE");
$this->db->or_where($array);
}
$query = $this->db->get();
$row['items'] = $query->result_array(); //
$result[$key] = $row;
OK this took some work, and I also had to do some adjustments in my view
So the problem can be broken down into two main components
1) Pass the results of the first query as an array to the second one using where_in
2) Reorder/regroup the results of the first array by item_id
My earlier code was doing the second component implicitly
So here is what I did (limits, offsets, ordering have been cut out to improve readablity)
function get_item_history($id)
{
//from metadata_history get item_id and corresponding metadata
$this->db->from('metadata_history')->where(array('id'=>$id, 'current_revision'=> "TRUE"));
$query = $this->db->get();
$result_query1 = $query->result_array(); //store this in an array
foreach ($result_query1 as $key-> $row){
$result[$row['item_id']]['meta_info'] = $row; //the first query contains meta info, that must be passed to the view
$selected_id_array[] = $row['item_id']; //Create a array to pass on to the next query
$result[$row['item_id']]['items'] = array(); //declare an array which will hold the results of second query later
}
$this->db->select('h.*');
$this->db->from('history h');
$this->db->where_in('h.item_id', $selected_id_array);
$this->db->where(array('h.current_revision' => 'TRUE'));
$query = $this->db->get();
$row = $query->result_array();
foreach ($row as $key => $datarow) {
$result[$datarow['item_id']]['items'][] = $datarow; //populate the array we declared earlier with results from second query
}
return $result; // Now this variable holds an array which is indexed by item id and contains the results of second query 'grouped' by item_id
}
So the number of queries have been cut from ~10 to 2.
On my local machine this saves ~50 msec/page, though I am not sure how this will do for larger databases.

Categories