I have to make a breadcrumb menu which comes database.
So made this function
function file_list($path) {
$result = array();
$q = "SELECT staticTitle,staticId,parentId FROM tbl_static_pages WHERE staticId = $path";
$run = mysql_query($q);
while($row = mysql_fetch_array($run)) {
if($row['parentId'] > 1) {
echo $row['staticTitle'];
$result = file_list($row['parentId']);
return $result; // INSERTED
}else {
return $result;
}
}
I have a database structure like this:
id | parentId | title
3 | 1 | keyword
28 | 3 | xxx
31 | 28 | business
I want to output like this business -> xxx -> keyword
I want to run this function until $row['parentId'] = 1.When I echo the title, I got correct result.When I try it to store it in array, I always get single value.
How can I return an array in recursive array?
I REALLY don't like the idea of recursive calls on the database. If this is a "breadcrumbs" database table, how big could it possibly be? ...I mean size is probably not a concern.
I would like to suggest that you pull the full table out (3 columns, all rows) and assign the resultset to a php variable. This means you only ever make one trip to the database -- and that's a good thing.
Code: (Demo)
function breadcrumber($array,$id){
static $result=[]; // declare the storage variable without losing elements during recursion
if(isset($array[$id])){ // if target exists
$result[]=$array[$id]['title']; // store title text
$parent=$array[$id]['parentId']; // assign new target
unset($array[$id]); // remove possibility of an infinite loop
breadcrumber($array,$parent); // recurse
}
return $result;
}
$resultset=[
['id'=>3,'parentId'=>1,'title'=>'keyword'],
['id'=>28,'parentId'=>3,'title'=>'xxx'],
['id'=>31,'parentId'=>28,'title'=>'business']
];
echo implode(' -> ',breadcrumber(array_column($resultset,NULL,'id'),31));
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-assign associative keys for easy lookup
Output:
business -> xxx -> keyword
...and here is another demo using your second set of data
Try this:
function file_list($path)
{
$result = array();
$q = "SELECT staticTitle,staticId,parentId FROM tbl_static_pages WHERE staticId = $path";
$run = mysql_query($q);
$results = array();
while ($row = mysql_fetch_array($run))
{
if ($row['parentId'] > 1)
{
echo $row['staticTitle'];
$results = array_merge($results, file_list($row['parentId']));
}
else
{
$results[] = $result;
}
}
return $results;
}
Few things that are not clear from your question:
Breadcrumbs are usually not recursive, so I suppose you do NOT want to actually return a recursive array (array where every element is again array). If you want, follow comment by #midhunjose
Do you expect the query to ever return multiple records?
Swap the order of array_merge arguments, if you want the parent before child in resulting array.
Try this:
$result[] = file_list($row['parentId']);
instand of
$result = file_list($row['parentId']);
Related
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
I have following model function:
function getdata_naoh($datetest2) {
$result = $this->db1->query("select round(avg(cast(t_dtl.hasil_m as decimal(6,4))),4) as hasil_m from t_hdr JOIN t_dtl ON t_hdr.headerid = t_dtl.headerid where id_solvent ='NaOH' AND status='ok' AND concentrate='0.0100' AND date_start <='$datetest2' AND date_finish >='$datetest2'");
if($result->num_rows()>0) {
return $result->result_array();
}else {
return array();
}
}
And a controller function:
function get_NaOH() {
$date_analysis = trim($this->input->post('date_analysis'));
$datetest = trim($this->input->post('date_analysis'));
$datetest2 = substr($datetest,6,4).'-'.substr($datetest,3,2).'-'.substr($datetest,0,2);
$dtnaoh = $this->M_tambahan->getdata_naoh($datetest2);
$data1 = 0;
foreach($dtnaoh as $row) {
$data1 = $row['hasil_m'];
}
$data = $data1;
echo $data;
}
The query result would be like:
| hasil_m |
| ----------- |
| 0.0100 |
I want to get hasil_m column, according to the controller function, i set variable data1 = 0
then in foreach statement change the value as a result from hasil_m but when i echo variable $data i still getting data1 value = 0, did i miss something ?
Any help would be appreciated greatly, thank you.
In your loop, you're overwriting the variable with the new value. If you want to sum all of the hasil_m data into $data1 then simply modify your foreach loop as the following:
foreach($dtnaoh as $row) {
$data1 += $row['hasil_m'];
}
For debugging purposes, could you update your question to show exactly what the query returns?
Edit
Seems you've got float's! You'll need to harness floatval() in your loop to pass the values through:
foreach($dtnaoh as $row) {
$data1 += floatval($row['hasil_m']);
}
This happens because your initial variable ($data1) is treated as a string. Meaning it doesn't and won't show the float values, treating it as a whole number.
There is probably something dumb I am doing wrong here.
public function get_scores($id)
{
$results = array();
$sql = "SELECT * FROM scores WHERE comp_id = $id";
$rows = $this->db->query($sql)->result();
foreach($rows as $row) {
if($row->confirmed_id) {
$results[$row->uid] += $row->score;
}
}
sort($results);
return $results;
}
So basically what I am trying to do is add all of the users scores in the database and return them in order of rank. confirmed->id is just a check to make sure the score has been confirmed (and thus is addable to their total score). I am basically trying to just make an associative array where the key is the users ID, and the score of each question they have in the database is added on. The query works fine, and $row-uid and $row->score both return the correct thing for every row, but $results[] never has anything added to it. If I even change it just to something silly like $results[3] = 0 at top, and then $results[3]++ or += 1 in the for loop, it doesn't add anything to $results[3].
EDIT: Problem solved. Indeed was something dumb -- confirmed_id was set to null by my partner when he reran our database after I had previously set it all to 1. Thanks guys :)
You are adding to $results[something] before it exists. You need to create it in the first case and then only increment it once it exists.
You need to remove the "+=" operation from the code. Check with this.
public function get_scores($id)
{
$results = array();
$sql = "SELECT * FROM scores WHERE comp_id = $id";
$rows = $this->db->query($sql)->result();
foreach($rows as $row)
if($row->confirmed_id)
$results[$row->uid] = $row->score;
sort($results);
return $results;
}
Your previous operation is similar to
$results[$row->uid] = $results[$row->uid] + $row->score;
So it will not add values to your row.
I am trying to get the sub-sections of sections recursively from the database. Right now, my code only gets the parents but not the children though. What modification do I have to do to this code to accomplish my goal? Thanx
function getSections()
{
$this->connectToDB();
// get list of sections that has no parents
$sql ="SELECT * FROM sections WHERE parent = 0 ORDER BY id ASC";
$result = mysql_query($sql);
while($row=mysql_fetch_array($result))
{
$thisID = $row['id'];
// recursivly get childeren
$childeren = $this->recursivlyGetSections($thisID);
// add to the final result
$toReturn .= "$thisID<br>$childeren";
}
// return final result
return $toReturn;
}
function getSections()
{
$this->connectToDB();
// get list of sections
$sql ="SELECT * FROM sections ORDER BY id ASC, parent ASC";
$result = mysql_query($sql);
$rezArray = array();
while($row=mysql_fetch_array($result))
{
if(!isset($rezArray[$row['parent']]))
$rezArray[$row['parent']] = array();
$rezArray[$row['parent']][] = $row;
}
//.. do something with the array
}
Use $rezArray which has all the results sorted by parent -- instead of doing multiple queries.
If you're wanting to store a full tree structure in your database, and it is read from more often that it is written to, you might want to consider implementing the storage as a nested set:
http://en.wikipedia.org/wiki/Nested_set_model
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.