i have a database that has an id_parent and id_child, but the id_child may also be parents of more ids, p_1(parent_1) has child 1-4, c_1(child_1) has child 6-9
p_1
|
c_1 , c_2, c_3, c_4
|
c_6, c_7, c_8, c_9
|
etc..
i have a function that gets the child by parent_id given a sql_table like so:
public function getChilds($folder_table, $folder_id){
if($this->connect){
$folder_id = $this->connection->real_escape_string((int)$folder_id);
$sql = 'SELECT * FROM '.$folder_table.' WHERE user_id=\''.$this->user_id.'\' AND folder_id=\''.$folder_id.'\'';
if($results = $this->connection->query($sql)){
$obj = $results->fetch_object();
return $obj;
}
}else{
$this->error = "Unable to connect to database. please make sure you can connect.";
}
return $this->error;
}
is there a way to continue executing this function continuously execute this function like a pyramid until there isn't any more ids to be fetch from any ids?
Attempt 1
i got all ids in a array like so:
$array_ids = array(1,2,3,4,5);
foreach($array_ids as $key => $value){
$new_ids = $obj->getChilds($sql_table, $value);
}
but this will only continue the process once more. i want this to continue until there isn't any more ids to get.
Related
I currently have the following:
$query='select concat("[",key,"=>",value,"]")
from table';
if(isset($query))$r=$mysql->query($query);
if(isset($r)){
for($i=1;$i<=$r->num_rows;$i++){
$r->data_seek($i-1);
$a[$i-1]=$r->fetch_array(MYSQLI_ASSOC);
$a[$i-1]=parse_array($a[$i-1]);
}
}
$mysql->close;
function parse_array($parent){
foreach($parent as$k=>$val){
if(strpos($val,']')){
$array=explode(',',substr($val,1,-1));
foreach($array as$val){
$keypair=explode("=>",$val);
$newarray[$keypair[0]]=$keypair[1];
}
$parent[$k]=parse_array($newarray);
}
}
}
There has to be a more elegant way of doing this - perhaps built into MySQL? I'm trying to minimize the time this spends running PHP - I would like it to arrive to PHP already in array form, but MySQL kicks Subquery returns more than one result if I attempt a subquery.
Edit: Here's table:
+----------+----------+
| value | key |
+----------+----------+
| img.jpg | src |
+----------+----------+
Output should be:
[
'src'=>'img.jpg'
]
Just move all of the manipulation over to php. Fetch the query with numeric indexes. Make the assumption that the every even index is a key and every odd index is a value (or vice versa).
$query = 'select key1, value1, key2, value2
from table';
if(isset($query))
$result = $mysql->query($query);
if(isset($result)) {
$newResult = []; // if your version of php doesn't support this syntax to create a new array use `$newResult = array();`
while($row=$result->fetch_array(MYSQLI_NUMERIC)) {
$newResult[] = build_assoc_array($row);
}
}
$mysql->close;
function build_assoc_array($flat_arr) {
$newArr = [];
$numCol = count($flat_arr);
for($colIndex = 0; $colIndex < $numCol; $colIndex+=2) {
$newArr[$flat_arr[$colIndex]] = $flat_arr [$colIndex+1];
}
return $newArr;
}
I have created a function which is using recursion to find out childs of Given User. as shown below :
function recursionFunc($param) {
$q = "select cust_id,amount,position from testtab where parent_id = $param";
$res = mysql_query($q);
static $i = 0;
while ($row = mysql_fetch_assoc($res)) {
$i++;
recursionFunc($row['cust_id']);
}
return array('totalChild'=>$i);
}
There are two cases:
I want to call recursionFunc() for each user i am having
Recursion will be done in order to find childs of a user.
Now i want to call this function in while loop in order to fetch childs of all user i am having.
Since i am using static variable $i to store the value of childs.
Now when function will be called for the first user it returns correct value of childs but return wrong value in all other cases.
AS show Below
$cutData = "select cust_id from testtab";
$ress = mysql_query($cutData);
while ($raw = mysql_fetch_assoc($ress)) {
$response = recursionFunc($raw['cust_id']);
echo '<pre>'.$raw['cust_id'];
print_r($response);
echo '<br>';
}
Outputs
1Array ( [totalChild] => 7 ) 2Array ( [totalChild] => 10 ) 3Array ( [totalChild] => 12 )
It will be great if you can help me .
Thanks in advance.
I've create a simple table of analogs:
+----+-------+-------+
| id | sku_1 | sku_2 |
+----+-------+-------+
| 1 | a1 | abcd |
| 2 | a2 | a3 |
| 3 | a3 | a1 |
+----+-------+-------+
3 rows in set (0.00 sec)
What it mean? It mean that product with article abcd has an analog with article a1, otherwise for example product with article a3 has an analog with article a1.
How to recursively get all the products from this table by a single article?
My solutions is wrong:
// Small Class to get analogs of products
class Analogs {
public function get_analogs($sku)
{
if (!$sku) return false;
$link = mysql_connect('localhost','','');
mysql_select_db('test');
$sku = mysql_real_escape_string($sku,$link);
$query = mysql_query("SELECT * FROM analogs WHERE sku_1='".$sku."' OR sku_2='".$sku."'");
while($analogs[]=mysql_fetch_assoc($query))
continue;
return $analogs;
}
public function MixedAnalogs($sku)
{
if (!$sku) return false;
$link = mysql_connect('localhost','','');
mysql_select_db('test');
$sku = mysql_real_escape_string($sku,$link);
$query = mysql_query("select sku_1 sku from analogs where sku_2 = '$sku' UNION
select sku_2 sku from analogs where sku_1 = '$sku'");
while($analogs[]=mysql_fetch_assoc($query))
continue;
return $analogs;
}
}
$mixed_analogs = AnalogsMix('abcd',$ids=array());
echo "<pre>";
print_r($mixed_analogs);
echo "</pre>";
// Recursive function to get analogs of analog
function AnalogsMix($sku,$ids=array())
{
$class_analogs = new Analogs();
$analogs = $class_analogs->get_analogs($sku);
foreach ($analogs as $analog)
{
$cross = null;
if ($analog['sku_1']==$sku)
{
$cross->sku = $analog['sku_2'];
}
else
{
$cross->sku = $analog['sku_1'];
}
$cross->id = $analog['id'];
if (!in_array($analog['id'],$ids))
{
$ids[] = $analog['id'];
$mixed[] = AnalogsMix($cross->sku,$ids);
}
}
if (isset($mixed))
{
return $mixed;
}
else
{
return false;
}
}
SQL UNION
select sku_1 sku from analogs where sku_2 = $yourid
union
select sku_2 sku from analogs where sku_1 = $yourid
Then you will get in results only ids of analogs.
Here, I suppose you have all your pairs in an array. For example, for your example, you would call analogsOf(array(array("a1", "abcd"), array("a2", "a3"), array("a3", "a1")), "abcd").
The idea is that you build a list of analogs containing initially only the string you are looking for and, every time you find an analog, you add it to the list of analogs and reiterate. You do so until you iterated the whole array of pairs without finding anything new.
function analogsOf(array $pairs, $key) {
$res = array($key); // The result, with only the given key
$i = 0; // Index of the current item
$changed = false; // Have we added an item to $res during that iteration ?
while ($i < count($pairs)) {
$current = $pairs[$i];
foreach ($res as $item) {
if (($current[0] === $item) && (!in_array($current[1], $res)) {
$res[] = $current[1];
$i = 0; // Reiterate as $res changed
}
else if (($current[1] === $item) && (!in_array($current[0], $res)) {
$res[] = $current[0];
$i = 0; // Reiterate as $res changed
}
else {
$i++; // Nothing found here, go to next item
}
}
}
return $res;
}
Note that this code was NOT tested, so there might be a few bugs here and there, but you've got the idea. Also note that I considered you could put the whole database content in an array, but that is probably not possible for obvious reasons, so you will probably have to adapt the code above.
I found a solution for this problem but the main problem in this approach is that.
it can make a loop like abcd->a1,a1->a3,a3->a2,a2->abcd. and it make recursive function endless and php throw an error. so you have to check for that if it is a big project.
in my solution i consider it parent-> child relation. and if a child found make it parent and check again and so on until there is no result.
let abcd is parent and after first execution a1 is child and relation is abcd->a1. but in next call a1 is parent and from first row of table it give a new relation that is a1->abcd and loop is endless.
To prevent checking in same row i use ID of last row from database and it now check row where id != ID (always check other row)
this is function i write, convert it according to your class and store the value in array as you like. I use a string only.
i knew it not a good solution but i works fine.
<?php
mysql_connect('localhost','','');
mysql_select_db('test');
function getSku($sku, $id, $rel = '') {
$query = mysql_query("SELECT * FROM analogs WHERE sku_1 = '$sku' AND id != '$id'" );
if (mysql_num_rows($query)) {
$row = mysql_fetch_assoc($query);
$sku = $row['sku_2']; //PARENT SKU
$id = $row['id']; //LAST ID
$rel .= $row['sku_1']. '-->' . $row['sku_2']. "<br>";
} else {
$query = mysql_query("SELECT * FROM analogs WHERE sku_2 = '$sku' AND id != '$id'" );
if (mysql_num_rows($query)) {
$row = mysql_fetch_assoc($query);
$sku = $row['sku_1']; //PARENT SKU
$id = $row['id']; //LAST ID
$rel .=$row['sku_2']. '-->' . $row['sku_1']. '<br>';
} else {
return (string)$rel; //NOTHING FOUND
}
}
return getSku($sku,$id,$rel);
}
echo $new = getSku('abcd','-1');
I am trying to make un-order list for parent child categories where if there is any child category than it will create another un-order list ( like indented text) so user can understand properly.
I have fetch sql but with foreach I don't understand how to set so where child category only will display under parent category by creating another un-order list under the parent category.
Here is my code
$query_cat = "SELECT * FROM ^categories";
$query = qa_db_query_sub($query_cat);
$catsid = qa_db_read_all_assoc($query);
echo '<UL>';
foreach ($catsid as $catid){
echo '<LI>'. $catid['title'].' '. $catid['categoryid'].'</LI>';
}
echo '</UL>';
So final result would be
First Category
Sub Category1
Second Category
EDIT:
After modified code with #vlcekmi3 answer https://stackoverflow.com/a/13451136/1053190 I am getting this result
Now how to exclude subcategory from parent list?
There's no really easy solution for this with your design. The most effective way would be to add column like order_in_list (and maybe depth_in_list).
They would be pre calculated in loop (pseudocode):
START TRANSACTION
UPDATE t1 SET order_in_list = 0 // Restart whole loop
$ids = array(0);
while $id = array_shift($ids){
$record = SELECT * FROM t1 WHERE id = $id // Get id details, order_in_list is important
$children = SELECT * FROM t1 WHERE parent_id = $id // get list of all childs
// If it's root element, start indexing from 0
$root_order = ($record ? $record->order_in_list : 1)
$child_no = count($children) // How many child will be adding
// No children, nothing to do:
if $child_no < 1{
continue;
}
append_to_array($ids, $children) // Store ids to process
// Shift all later records, we'll be creating gap in order_in_list 1,2,3,4,5
// To 1,2,5,6,7 to insert items on places 3,4
UPDATE t1 SET order_in_list = (order_in_list + $child_no)
WHERE order_in_list > $record->order_in_list
// Okay, set IDs for direct children
foreach( $children as $child){
UPDATE t1 SET order_in_list = $root_order, depth_in_list = $record->depth_in_list+1
WHERE id = $child->id
$root_order++;
}
}
COMMIT
This way you'll get records like:
First category, 1, 1
Second category 3, 1
Sub category, 2, 2
Which you could display with simple loop:
$last_depth = 0;
foreach( (SELECT * FROM t1 ORDER by `order_in_list`) as $row){
if( $last_detph > $row['depth_in_list'])){
// Close level </ul>
} else if($last_detph < $row['depth_in_list']){
// Opening level <ul>
} else {
// The same depth
}
$last_depth = $row['depth_in_list'];
}
Without modifying database
It would be probably most effective to build two arrays containing root elements and all elements:
$root_elements = array();
$all_elements = array();
foreach( (SELECT * FROM t1) as $row){
// Store details into all_elements, note that entry may have already be created when
// processing child node
if( isset( $all_elements[$row['id']])){
// set details
} else {
$all_elements[$row['id']] = $row;
$all_elements[$row['id']]['children'] = array(); // Array of child elements
}
if( $row['parent_id'] == NULL){
$all_elements[] = $row['id']; // Add row element
} else {
if( isset( $all_elements[ $row[ 'parent_id']])){
$all_elements[ $row[ 'parent_id']]['children'][] = $row['id'];
} else {
// Create new record:
$all_elements[ $row[ 'parent_id']] = array();
$all_elements[ $row[ 'parent_id']]['children'] = array($row['id']);
}
}
}
And then write it as:
foreach( $root_elements as $element_id){
write_recursive( $all_elements[ $element_id]);
}
// And display
function write_recursive( $element)
{
echo '<ul>...';
if( count( $element['children'])){
foreach( $element['children'] as $child){
write_recursive( $all_elements[ $child]);
}
}
echo '</ul>';
}
You better create class for that (to replace using global variables), but you should have a solid way to do this. Anyway try avoid using this with large number of records (I wouldn't go past 2000-5000 menu entries), try to at least cache it.
Note: solutions are oriented towards minimal number of requests on database when displaying list.
you can use complicated query or something like this
foreach ($catsid as $catid) {
...
$subquery_cat = "SELECT * FROM ^categories WHERE parentid='".$catid['categoryid']."'";
$query = qa_db_query_sub($subquery_cat);
$subcatsid = qa_db_read_all_assoc($query);
// wrap into html
...
}
I have a table like this:
id
name
parent_id
I then want to select certain rows based on their id, so something like this:
SELECT *
FROM TABLE
WHERE id IN ('1', '5', '8', '9', '35')
I want to, from this query, also show the parent/child relationship, like:
id parent
-----------
1 0
5 1
8 0
9 8
35 9
So the final output would look something like this:
1
--5
8
--9
----35
Do I do this outside of mysql, i have tried using arrays, but can't figure it out, or
Do I do it inside MYSQL, which i don't know how to do that either.
Here is what I was able to come with which seems to be working great.
PS-Sorry about the formatting, can't figure it out :( (fixed?)
I grab my parent_id and id from MYSQL and put it into an arraly where the array keys are the id's and the values are the parents, so with in the while loop for mysql, something like this: $testarray[$id] = $parent_id;
Then I run it through the functions below, and it orders it just how I need it.
function retrieveSubTree($parent, $myarray) {
$tempArray = $myarray;
$array = array();
//now we have our top level parent, lets put its children into an array, yea!
while ($child = array_search($parent, $tempArray)) {
unset($tempArray[$child]);
//now lets get all this guys children
if (in_array($child, $tempArray)) {
$array[$child] = retrieveSubTree($child, $tempArray);
} else {
$array[$child] = true;
}
}//end while
return (!empty($array)) ? $array : false;
}
function retrieveTree($myarray) {
$array = array();
$counter = 0;
foreach ($myarray as $key => $value) {
$child = $key;
$parent = $value;
//if this child is a parent of somebody else
if (in_array($child, $myarray) && $parent != '0') {
while ($myarray[$parent] != '' && $myarray[$parent] != '0') {
$newparent = $myarray[$parent];
$parent = $newparent;
}
if (!array_key_exists($parent, $array)) {
$array[$parent] = retrieveSubTree($parent, $myarray);
}
} else {
//now make sure they don't appear as some child
if (!array_key_exists($parent, $myarray)) {
//see if it is a parent of anybody
if (in_array($child, $myarray)) {
$array[$child] = retrieveSubTree($child, $myarray);
} else {
$array[$child] = true;
}
}//end if array key
}//end initial in array
}//end foreach
return (!empty($array) ? $array : false);
}
$test = array(
'1'=>'15',
'2'=>'1',
'3'=>'1',
'4'=>'0',
'5'=>'0',
'6'=>'4',
'7'=>'6',
'8'=>'7',
'9'=>'2',
'10'=>'9'
);
print_r(retrieveTree($test));
Without changing your table structure, this requires recursion, which MySQL does not support. You'll have to do it elsewhere. You can write a recursive function in PHP to use, for example, breadth-first search to build your array. Here it looks like you are using parent_id of 0 to denote a top-level object. You can search over your results, and add to your array every object whose parent is zero, which will give you an array with 1 and 8. Then you can recurse: find all the results with a parent of 1, and add that as a subarray to 1; then find all the results with a parent of 8 and add those as a subarray of 8. Continue doing this for each level until you've run out of results.
As other posters pointed out, you can do this natively in MySQL if you can change the table structure.