Restructure array from sql query so that I can echo proper values - php

I'm trying to get the content I need from a joined query and properly use values as an array key so that I can build some DIV lists properly
My php query and array:
$getTickers = "
SELECT d.ID as displayID, d.display_name as display, l.location_name as locationName, d.location_id as location, t.id as ticker, tc.id as contentID, tc.content
FROM displays d
INNER JOIN locations l on d.location_id = l.id
INNER JOIN tickers t on d.id = t.display_id
INNER JOIN ticker_content tc on t.id = tc.ticker_id;
";
$tickers = $mysqlConn->query($getTickers);
$tickerDisplays = array();
foreach($tickers as $subArray) {
if(!array_key_exists($subArray['displayID'], $tickerDisplays)) {
$tickerDisplays[$subArray['displayID']] = array();
}
// here you add `display_name` under key `display_id`
$tickerDisplays[$subArray['displayID']][$subArray['location']] = $subArray['display'];
}
All examples and code below, but I don't need the html structure help with this, just how to restructure the array/key to give me the desired results and how I should loop them on the front end.
I'm getting 4 divs as I expect right now (one for each unique display/location)
but I need to figure out how to correcty arrange it so I can echo the DIsplay name as the h4, the location as h5, and then each content in my list
So the query result gives me this:
displayID | display | locationName | location | ticker | contentID | content |
1 Office Building 4 4 1 1 testing content
2 Lobby Building 4 4 2 2 testing content 2
3 Lobby Building 1 1 3 3 testing content 3
4 Office Building 1 1 4 4 testing content 4
4 Office Building 1 1 4 5 testing content again
I'm trying to loop on this with the expected result of having a a div for each location/display combo like so:
OFFICE
Building 4
testing content
---------------
LOBBY
Building 4
testing content 2
------------------
LOBBY
Building 1
testing content 3
------------------
OFFICE
Building 1
testing content 4
testing content again
----------------------
Here's the way I'm currently trying to loop that
<?php foreach($tickerDisplays as $key => $ticker):?>
<h4><?php echo $key ?></h4> //so this should be the display Name (office, lobby)
<h5><?php echo //location?></h5> //this should be the location name (Building 1, Building 4)
//This will be another foreach for any content associated with the location/display
<ul class="tickerContent">
<li>
</ul>
</div>
</div>
<?php endforeach;?>

The approach here is to make a child array for each display line to contain all
the multiple content records.
// Dummy the data from the query
$tickers = [
['displayID' => 1, 'display' => 'Office', 'locationName' => 'Building 4', 'location' => 4, 'ticker' => 1, 'contentID' => 1, 'content' => 'testing content'],
['displayID' => 2, 'display' => 'Lobby', 'locationName' => 'Building 4', 'location' => 4, 'ticker' => 2, 'contentID' => 2, 'content' => 'testing content 2'],
['displayID' => 3, 'display' => 'Lobby', 'locationName' => 'Building 1', 'location' => 1, 'ticker' => 3, 'contentID' => 3, 'content' => 'testing content 3'],
['displayID' => 4, 'display' => 'Office', 'locationName' => 'Building 1', 'location' => 1, 'ticker' => 4, 'contentID' => 4, 'content' => 'testing content 4'],
['displayID' => 4, 'display' => 'Office', 'locationName' => 'Building 1', 'location' => 1, 'ticker' => 4, 'contentID' => 5, 'content' => 'testing content again']
];
// A place to keep the reorganized data
$tickerDisplays = [];
// Walk through the query result
foreach($tickers as $row) {
$displayID = $row['displayID']; // for convenience and readability
$location = $row['location']; // for convenience and readability
$display = $row['display'];
$contentID = $row['contentID'];
if ( ! array_key_exists($row['displayID'], $tickerDisplays) ) {
$tickerDisplays[$displayID] = [
'displayID' => $row['displayID'],
'display' => $row['display'],
'ticker' => $row['ticker'],
'contentID' => $row['contentID'],
'content' => $row['content'],
'location' => $row['location'],
'locationName' => $row['locationName'],
'#content' => [] // to store the content data
];
}
$tickerDisplays[$displayID]['#content'][$contentID] = ['content' => $row['content']];
}
print_r($tickerDisplays);
foreach ( $tickerDisplays as $key => $ticker ) {
// Output the display and location name
out($ticker['display']);
out($ticker['locationName']);
// Output all the content records.
foreach ( $ticker['#content'] as $contentID => $content ) {
out($content['content']);
}
out('------------');
}
// Just a utility function
function out($msg) {
echo "$msg\n";
}
Output:
Office
Building 4
testing content
------------
Lobby
Building 4
testing content 2
------------
Lobby
Building 1
testing content 3
------------
Office
Building 1
testing content 4
testing content again
------------

Related

How to create a php mysql dynamic tree

How can using php mysql create a dynamic tree for this tables
tbl_folder
db_id db_foldername
1 accounting
2 hr
3 it
tbl_subfolder
db_id db_folderid db_subfoldername
1 1 xxx
2 1 yyy
3 2 zzz
tbl_childsubfolder
db_id db_subfolderid db_childsubfoldername
1 1 ffff
2 2 llll
tbl_subchild
db_id db_childsubfolderid db_subchildname
1 1 eee
2 1 ppp
accounting
xxx
fff
eee
ppp
yyy
lll
hr
zzz
it
include("include/connect.php");
--SELECT--
$name";
}
?>
if(isset($_POST['add'])){
$foldername=$_POST['txt_name'];
$select=$_POST['txt_select'];echo $select;
$explod=explode("-",$select);
$path=$explod['0'].';'.$explod['1'];
if($path==";"){$path="";}
$parent_id=$explod['1'];
if($foldername==""){echo"enter a name";}
else{
$insert_query=mysqli_query($conn,"insert into tbl_folders(parent_id,path,name)values('$parent_id','$path','$foldername')")or die(mysqli_error($conn));
header("location:index.php");
}
}
$sql=mysqli_query($conn,"select * from tbl_folders where parent_id='0'")or die(mysqli_error($conn));
while($row=mysqli_fetch_array($sql)){
$name=$row['name'];
$id=$row['db_id'];
echo $name;echo"<br/>";
$sqli=mysqli_query($conn,"select * from tbl_folders where parent_id='$id'")or die(mysqli_error($conn));
while($row=mysqli_fetch_array($sqli)){
$name=$row['name'];
$id=$row['db_id'];
$path=$row['path'];
$x=explode(";",$path);echo $path;echo"<br/>";
$pa=$x['1'];
echo $name;echo"<br/>";
$sqli=mysqli_query($conn,"select * from tbl_folders where parent_id='$id' and path='$pa'")or die(mysqli_error($conn));
while($row=mysqli_fetch_array($sqli)){
$name=$row['name'];
$id=$row['db_id'];
$path=$row['db_path'];
echo $name;echo"<br/>";}
}
}
Building the tree
You can build one table with the following fields:
`id (int), parent_id (int), path (vachar), name`
id - is the identifier
parent_id - refers to the id of the parent in the same table
path - is the path of parent ids to the given element
Example entries in the table:
|id | parent_id | path | name|
-------------------------------
|1 | 0 | | A |
-------------------------------
|2 | 1 |;1; | B |
-------------------------------
|3 | 2 |;1;2; | C |
where A is the parent, B is child of A, and C is child of B.
In your backend logic you need to have the following:
When you add/edit new item in this table - if it is root parent (with no parents above it) you insert it with parent_id=0 and path=''
When you add/edit new item in this table - if it has parent then you insert it with parent_id=:idOfParent and path=CONCAT(:parentPath, ';', :idOfParent, ';')
where :idOfParent - is the parent id value and :parentPath is the path of the parent which you concatenate with the ;:idOfParent;
; - is the separator for the ids in the path
Path column gives you the advantage of directly getting all the parents of given element without using recursive approaches.
So if you select an item with path ';1;2;3;' and you need the info for the parents also you will have 1 + 3 SELECT queries in total.
And when deleting an item you can do this:
DELETE FROM table WHERE path LIKE (';:deleteId;')
where :deletedId is the id of the deleted element. This query will delete all the entries that have deleted item as a parent.
Visualization of the tree
you can get the $data with this query
'SELECT id, parent_id, path, name FROM table WHERE 1;'
But for the test i use the following example array
$data = [
0 => ['id' => 1, 'parent_id' => 0, 'path' => '', 'name' => 'A'],
1 => ['id' => 2, 'parent_id' => 1, 'path' => ';1;', 'name' => 'B'],
2 => ['id' => 3, 'parent_id' => 2, 'path' => ';1;2;', 'name' => 'C'],
3 => ['id' => 4, 'parent_id' => 3, 'path' => ';1;2;3;', 'name' => 'D'],
4 => ['id' => 5, 'parent_id' => 1, 'path' => ';1;', 'name' => 'E'],
5 => ['id' => 6, 'parent_id' => 2, 'path' => ';1;2;', 'name' => 'G'],
6 => ['id' => 7, 'parent_id' => 0, 'path' => '', 'name' => 'H'],
];
$ref = null;
$tree = [];
foreach($data as $item) {
if($item['path']) {
$path = ltrim($item['path'], ';');
$path = rtrim($path, ';');
$pathArray = explode(';', $path);
$i = 0;
foreach($pathArray as $parentId) {
if($i === 0) {
if(!isset($tree[$parentId])) {$tree[$parentId] = ['name' => [], 'children' => []];}
$ref = &$tree[$parentId]['children'];
}
else {
if(!isset($ref[$parentId])) $ref[$parentId] = ['name' => [], 'children' => []];
$ref = &$ref[$parentId]['children'];
}
$i++;
}
if($ref !== null) {
$ref[$item['id']]['name'] = $item['name'];
$ref[$item['id']]['children'] = [];
}
}
else {
$tree[$item['id']]['name'] = $item['name'];
$tree[$item['id']]['children'] = [];
}
}
Output part:
print '<pre>';
print_r($tree);
print '</pre>';
So here you change the code according to your needs. Print it in the way you want (may be you will need recurrsion to access every tree node)

Mysql one Parent multiple Child result without repeating Parent rows

I am building a CMS with Codeigniter and MYSQL. and have a table like this.
CREATE TABLE parent
(`parentId` int, `parentName` varchar(50));
INSERT INTO parent
(`parentId`, `parentName`)
VALUES
(1, 'Movie'),
(2, 'Food'),
(3, 'Sports');
CREATE TABLE child
(`childId` int, `parentId` int,`childName` varchar(50));
INSERT INTO child
(`childId`, `parentId`, `childName`)
VALUES
(1, 1, 'Harry Potter'),
(2, 3, 'Foot Ball'),
(3, 2, 'Pizza'),
(4, 2, 'Burger'),
(5, 1, 'Avengers'),
(6, 1, 'Fury'),
(7, 3, 'Cycling');
And want output to be printed output like this
foreach($parent as $parentData):
echo"<h4>".$parentData->parentName."</h4>";
echo"<ul>";
foreach($child as childData):
echo"<li>".$childData->childName."</li>";
endforeach;
echo"</ul>"
endforeach;
which produces this
<h4>Movie</h4>
<ul>
<li>Harry Potter</li>
<li>Avengers</li>
<li>Fury</li>
</ul>
<h4>Food</h4>
<ul>
<li>Pizza</li>
<li>Burger</li>
</ul>
<h4>Sports</h4>
<ul>
<li>Foot Ball</li>
<li>Cycling</li>
</ul>
Any tweaking of the code is welcomed.
As i have been trying this for the past few hours.
Thanks in advance.
Update:
I implemented the answer to my code as CodeGodie suggested and added a view like this.
foreach ($result as $arr) {
if (!isset($final[$arr["parentName"]])) {
$final[$arr["parentName"]] = array();
}
array_push($final[$arr["parentName"]], $arr);
}
foreach ($final as $parent=> $childs) {
echo $parent."<br>";
foreach ($childs as $child) {
print_r($child) ;
}
}
Now i got the result i was expecting
There are multiple ways of doing this. However I would use the following approach:
You need to create the following SQL query:
SELECT * FROM parent p
JOIN child c ON c.parentId = p.parentId
ORDER BY parentName
Or in Codeigniter:
$this->db->select("*");
$this->db->from("parent p");
$this->db->join("child c", "c.parentId = p.parentId ");
$this->db->order_by("parentName");
$q = $this->db->get();
return $q->result_array();
which will give you a result of something like this:
$result = array(
array(
"parentId" => 2,
"parentName" => "Food",
"childId" => 3,
"childName" => "Pizza",
),
array(
"parentId" => 2,
"parentName" => "Food",
"childId" => 4,
"childName" => "Burger",
),
array(
"parentId" => 1,
"parentName" => "Movie",
"childId" => 1,
"childName" => "Harry Potter",
),
array(
"parentId" => 1,
"parentName" => "Movie",
"childId" => 5,
"childName" => "Avengers",
)
);
Iterate through your results:
foreach ($result as $arr) {
if (!isset($final[$arr["parentName"]])) {
$final[$arr["parentName"]] = array();
}
array_push($final[$arr["parentName"]], $arr);
}
var_dump($final);
this will give you a result like this which you can then iterate to build your HTML:
array (size=2)
'Food' =>
array (size=2)
0 =>
array (size=4)
'parentId' => int 2
'parentName' => string 'Food' (length=4)
'childId' => int 3
'childName' => string 'Pizza' (length=5)
1 =>
array (size=4)
'parentId' => int 2
'parentName' => string 'Food' (length=4)
'childId' => int 4
'childName' => string 'Burger' (length=6)
'Movie' =>
array (size=2)
0 =>
array (size=4)
'parentId' => int 1
'parentName' => string 'Movie' (length=5)
'childId' => int 1
'childName' => string 'Harry Potter' (length=12)
1 =>
array (size=4)
'parentId' => int 1
'parentName' => string 'Movie' (length=5)
'childId' => int 5
'childName' => string 'Avengers' (length=8)
Hope this helps
I think you are looking for group concat
https://www.percona.com/blog/2013/10/22/the-power-of-mysqls-group_concat/
Using this, you can select a comma separated list of child values. Then in your PHP you would simply need to explode on the comma and then loop through that.
Bear in mind the default group_concat limit is often quite low so you will probably need to increase this - https://dev.mysql.com/doc/refman/5.1/en/server-system-variables.html#sysvar_group_concat_max_len
This query will get all the data:
SELECT parent.parentName, child.childName
FROM parent
INNER JOIN child on parent.parentId = child.parentId;
And return it as:
------------------------------
parentname | childName
------------------------------
Movie | Harry Potter
Movie | Avengers
Movie | Fury
et cetera...

Pull count of records in a table that have the same value with Codeigniter Active Record

I am working on a site where I have a table with "catches" (people have caught fish with a particular lure). The lure_used category is an integer.
I want to find the users "best lure". So i want to loop through all the user_catches rows and return an array that has each lure and how many times it was used.
So for example we might have
catch_1 | lure_used = 5,
catch_2 | lure_used = 3,
catch_3 | lure_used = 6,
catch_4 | lure_used = 3,
so from that i would like to know that 5 and 6 occur 1 time while 3 occurs twice. Therefore 3 is the most successful lure.
I know that I could probably use "MAX" in mysql queries, but i'm not really farmiliar with it and attempts have failed.
I have been able to create an array of lures used like:
$lures = array(5, 3, 6, 3);
So maybe i could just loop through that and output something like...
5 = 1, 3 = 2, 6 = 1.
I guess i'm grasping at straws haha, anyone have a better idea on how to get this done?
Here are all the fields in the "user_catches" table:
'id' => $row->id,
'user_id' => $row->user_id,
'species' => $row->species,
'season' => $row->season,
'lure_used' => $row->lure_used,
'depth' => $row->depth,
'exact_depth' => $row->exact_depth,
'presentation' => $row->presentation,
'catch_weight' => $row->catch_weight,
'length' => $row->length,
'fishing_from' => $row->fishing_from,
'moon_phase' => $row->moon_phase,
'water_temp' => $row->water_temp,
'water_quality' => $row->water_quality,
'notes' => $row->notes,
'rod' => $row->rod,
'reel' => $row->reel,
'line' => $row->line,
'rig' => $row->rig,
'catch_image' => $row->catch_image,
'weather' => $row->weather,
'temp' => $row->temp,
'humidity' => $row->humidity,
'wind' => $row->wind,
'pressure' => $row->pressure,
'visibility' => $row->visibility,
'location' => $row->location,
'weather_icon' => $row->weather_icon,
'catch_date' => $row->catch_date,
SELECT lure, count (*) as count
from user_catches
GROUP BY lures
ORDER BY count;

Best match using MySQL and PHP

I'm tackling my first project using PHP/MySQL in which I have a list of cities and ratings from 1-5 in certain categories (Food, Shopping, etc.). What I'm wanting to do is evaluate each row (each City), when a form is submitted on whether the categories are important or not.
This is how I want it to work.
Say, for example:
1. Chicago Food: 4, Shopping: 4, Nightlife: 4
2. New York Food: 4, Shopping: 5, Nightlife: 5
3. Boston Food: 5, Shopping: 4, Nightlife: 3
(the ratings are just for example)
And the user says that Food isn't important. Therefore the code will only evaluate Shopping and Nightlife... New York ends with 10, Chicago with 8 and Boston with 7.
As I have a list of around 35-40 cities that I want to evaluate on each category (if the user deems it "important") dynamically, and the winner will be the highest number at the end of the evaluation.
Does anyone have any ideas on how to go about this? I have the table built in MySQL with all the ratings, just need to write the code out now.
What I've tried: bringing in all of the values using arrays, but I've found it difficult to loop through each of the rows... help!
You can accomplish this task with just a little bit of PHP code and an appropiate SQL statement.
Here is a possible solution:
$important_cat = $_POST['categories']; //which is an array
$sql = "SELECT city, sum(".implode(' + ',$important_cat).") AS cat
FROM tbl
ORDER BY cat DESC";
//query sql
Assuming database tables similar to this (at least, they should be normalized in this fashion):
city ( id, name );
category ( id, name );
rating ( city_id, category_id, rating );
... with an array of interests similar to this:
$interests = array(
'Food',
'Shopping'
);
... the following sql:
$sql = 'SELECT
city.name as city,
GROUP_CONCAT( category.name || ": " || rating.rating, ", " ) as ratings,
SUM( rating.rating ) as totalRating
FROM
rating
JOIN
city
ON city.id = rating.city_id
JOIN
category
ON category.id = rating.category_id
WHERE
category.name IN( ' . implode( ',', array_map( array( $db, 'quote' ), $interests ) ) . ' )
GROUP BY
city.name
ORDER BY
totalRating DESC';
(I assumed the use of PDO, utilizing PDO::quote() for escaping here, but substitute the callback array( $db, 'quote' ) with whatever quoting/escape mechanism your mysql library offers)
... will yield a result set similar to this (I've populated random rating data for my example):
array (
0 => array (
'name' => 'Chicago',
'ratings' => 'Food: 3, Shopping: 3',
'totalRating' => '6'
),
1 => array (
'name' => 'New York',
'ratings' => 'Food: 1, Shopping: 4',
'totalRating' => '5'
),
2 => array (
'name' => 'Seattle',
'ratings' => 'Food: 4, Shopping: 1',
'totalRating' => '5'
),
3 => array (
'name' => 'Los Angeles',
'ratings' => 'Food: 2, Shopping: 2',
'totalRating' => '4'
),
4 => array (
'name' => 'Boston',
'ratings' => 'Food: 1, Shopping: 2',
'totalRating' => '3'
),
5 => array (
'name' => 'San Francisco',
'ratings' => 'Food: 1, Shopping: 1',
'totalRating' => '2'
)
)
If you only need the first result, append LIMIT 1 to the sql query.
This should give you an idea of how to go about accomplishing what you want.
Above all: let MySQL do all the work (filtering, sorting) — not PHP.

Retrieve Child Objects

I want a table of comments like so
id | comment | parent_id
--------------------------
1 text1 0
2 text2 1
3 text3 2
4 text4 3
5 text5 3
6 text6 5
I want to construct an array displaying the hierarchy of the parents and children. The tree should go back a undetermined number of generations. I don't want to use nesting foreach loops as I'm not sure how deep it goes. That is why I'm here, I'm not sure of the best practice for a problem like this. I also want to display the depth in the array. Below is an example. It doesn't really relate to table above, but hopefully gives you an idea of what I need.
array(
"depth"=> 4
"parent" => array(
"id"=> 1,
"comment" => "sometext1"
"child_count" => 2,
"children" => array(
0 => array(
"id" => 2
"comment" => "sometext2",
"child_count" => 0,
"children" => null
),
1 => array(
"id" => 3
"comment" => "sometext3"
"child_count" => 1,
"children" => array(
0 => array(
"id" => 2
"comment" => "sometext2",
"child_count" => 2,
"children" => array(
0 => array(
"id" => 2
"comment" => "sometext2",
"child_count" => 0,
"children" => null
),
1 => array(
"id" => 2
"comment" => "sometext2",
"child_count" => 1,
"children" => array(
"id" => 2
"comment" => "sometext2",
"child_count" => 0,
"children" => null
)
)
)
)
)
)
)
)
I was going to use foreach and do a SQL statement to retrive that parent/childs children. ie
$sql = "SELECT * FROM comments WHERE parent = $parent_id";
Im not really looking for the code for all this, just a pseudo code solution.
This can be easily done in PHP... For this you need two arrays and a two while loops.
This code will make a tree the way you wanted and for an undetermined depth and number of children.
Pastebin to the working code.
Using references, lets imagine everything is saved in an array $data with this structure: (id, comment, parent_id) where parent_id points to an id.
Code to build the tree.
$tree = array();
reset($data);
while (list($k, $v) = each($data))
if (0 == ($pid = $v['parent_id']))
$tree[$k] =& $data[$k]; else
$data[$pid]['children'][$k] =& $data[$k];
And to generate the depth and child count.
reset($data);
while (list($k, $v) = each($data))
if (0 != $v['parent_id'])
{
$ref =& $data[$k];
$depth = 0;
do
{
if ($depth) $ref =& $data[$ref['parent_id']];
$dre =& $ref['depth'];
if (!isset($dre) || $dre <= $depth) $dre = $depth++;
if (isset($ref['children']))
$ref['child_count'] = count($ref['children']);
else
{
$ref['child_count'] = 0;
$ref['children'] = null;
}
}
while ($ref['parent_id']);
}
All my code has been written on the fly and not even tested, so if there are any errors please forgive meeeeeeeee!!!!!!!!!!! ← Forget that, I tried it, fixed a couple of issues and now works perfectly.
Note
For this code to work, the index of every item has to be equal to its ID.
The array I used to try the code.
$data = array(
'1' => array('id' => '1', 'comment' => 'a', 'parent_id' => 0),
'2' => array('id' => '2', 'comment' => 'b', 'parent_id' => 0),
'3' => array('id' => '3', 'comment' => 'c', 'parent_id' => 1),
'4' => array('id' => '4', 'comment' => 'd', 'parent_id' => 1),
'5' => array('id' => '5', 'comment' => 'e', 'parent_id' => 2),
'6' => array('id' => '6', 'comment' => 'f', 'parent_id' => 2),
'7' => array('id' => '7', 'comment' => 'g', 'parent_id' => 5),
'8' => array('id' => '8', 'comment' => 'h', 'parent_id' => 7)
);
This is the problem when you use Adjacency list for trying to retrieve all child nodes in the hierarchy. It just doesn'y handle recursion very well if you are using mysql. (Oracle is another matter).
Creating the structure is simple, you should not really concern yourself with how to create the array structure just yet, first you want to try and create an efficient query and effiecient models that play perfectly to the type of queries that you will be making.
For example, you say that you want to retrieve all child nodes. Well then you should probably be using nested set models instead or in addition to adjacency list.
Take a look at some of these resources...
Is there a simple way to query the children of a node?
The idea of a nested set, is that you store the lft and right edge values of a node, meaning that retrieving any child nodes, is incredibly simple, beause you just select nodes which have a lft value greater than the target nodes lft value, and smaller than the rgt value.
Once you retrieve your result set, creating your array structure will be effortless.
See here : http://en.wikipedia.org/wiki/Nested_set_model
Once you have your results, then take a look at this question, which I asked a year or so ago, which is exactly what you want. PHP > Form a multi-dimensional array from a nested set model flat array
Example
id | comment | parent_id | lft | rgt |
-------------------------------------------------
1 World null 1 12
2 Europe 1 2 11
3 England 2 3 10
4 Kent 3 4 5
5 Devon 3 6 9
6 Plymouth 5 7 8

Categories