I have a table that looks like this.
pers_id pers_name pers_date pers_date_attend_ind
431 Bacon 1/14/2013 N
431 Bacon 1/27/2013 N
431 Bacon 1/28/2013 N
431 Bacon 2/17/2013 N
I'd like to display it in php like
<date 1> <date 2> <Date 3>
Bacon N N N
I'm at a loss for how to do that.
Assume your $rows variable will looks after fetching results like this:
$rows = array(0 => array('pers_id' => 431, 'pers_name' => 'Bacon', 'pers_date' => '1/14/2013', 'pers_date_attend_ind' => 'N'),
1 => array('pers_id' => 431, 'pers_name' => 'Bacon', 'pers_date' => '1/27/2013', 'pers_date_attend_ind' => 'N'),
2 => array('pers_id' => 431, 'pers_name' => 'Bacon', 'pers_date' => '1/28/2013', 'pers_date_attend_ind' => 'N'),
3 => array('pers_id' => 431, 'pers_name' => 'Bacon', 'pers_date' => '2/17/2013', 'pers_date_attend_ind' => 'N'),
);
Then I played with this array to make it look like this:
Array
(
[431] => Array
(
[name] => Bacon
[dates] => Array
(
[1/14/2013] => N
[1/27/2013] => N
[1/28/2013] => N
[2/17/2013] => N
)
)
)
using foreach loop:
foreach($rows as $value)
{
$array[$value['pers_id']]['name'] = $value['pers_name'];
$array[$value['pers_id']]['dates'][$value['pers_date']] = $value['pers_date_attend_ind'];
}
Now it looks much better for your table(s) preparation. I created a function what returns a table(s) as you set in your question based on this modified array.
function generate_table($array)
{
$html = '';
foreach($array as $value)
{
$html .= '<table>'; // start table inside the loop. It will looks better due to each member may have different number of date count.
$html .= '<tr>';
$html .= '<td> </td>';
foreach($value['dates'] as $k => $v)
{
$html .= '<td>' . $k . '</td>';
}
$html .= '</tr>';
$html .= '<tr>';
$html .= '<td>' . $value['name'] . '</td>';
foreach($value['dates'] as $v)
{
$html .= '<td>' . $v . '</td>';
}
$html .= '</tr>';
$html .= '</table>';
}
return $html;
}
This function looks a bit nasty, but it works. It's on you to improve this function if you want.
Live previews
Preview for single user
Preview for multiple users
Preview of result
What you want is a simple SELECT query to get all pers_date and pers_date_attend_ind for one person and limit it to three results only.
SELECT `pers_date`, `pers_date_attend_ind` FROM `table` WHERE `pers_id` = 431 ORDER BY `pers_date` DESC LIMIT 3
Then just fetch the results and print them with php.
Unfotunately mysql doesn have magic function to transform values wich are variables to column names , But in your case you should have an extra column (date_number i have added it in demo) which count the number of dates added.
here is aproach to it:
select `pers_name`,
max(case when `date_number` = 1 then `pers_date_attend_ind` end) as date1,
max(case when `date_number` = 2 then `pers_date_attend_ind` end) as date2,
max(case when `date_number` = 3 then `pers_date_attend_ind` end) as date3,
max(case when `date_number` = 4 then `pers_date_attend_ind` end) as date4
from Table1
HERE demo to play with
Related
I need an advice how to display data from array (result of sql query) in PHP.
Here's the problem:
My query result is 2 row (top figure). Currently, I'm using foreach method to display all data, thus, the foreach will iterate 2 times, right?
Now, I want to ask:
In my web page, how I can display like the bottom figure??
How to join the second row (the theory's score is 0, and the lab's score is 75 and 80) to the first row? So it'll be ONLY 1 row for ID 112.
EDIT:
The SQL query is not my part. I've just received that data (top figure), and my job only to display it to web page.
Well as you used to display rows with foreach you could do it the same way:
* create new array
* loop through your current array
* save to new array by ID and do SUMs
* you can do output from newly created array.
create new array by loop through your current array which will filter out 0 values probably by using array_walk_recursive() or array_map() or array_filter()
then at this stage you got filtered array
you can do output from filtered array
I'm wondering why you have two rows with same 'id'. Usually 'id' should be the primary key...
Anyway, you could simply combine the rows with same 'id', adding the equally named fields casting them like integers.
EDIT 1-2:
Supposing code is in associative arrays:
$rows = array(
0 => array(
'id' => 112,
'theory' => array('score1' => 70, 'score2' => 80),
'lab' => array('score1' => 0, 'score2' => 0)
),
1 => array(
'id' => 112,
'theory' => array('score1' => 0, 'score2' => 0),
'lab' => array('score1' => 75, 'score2' => 80)
),
2 => array(
'id' => 110,
'theory' => array('score1' => 0, 'score2' => 0),
'lab' => array('score1' => 75, 'score2' => 80)
)
);
// New buffer for data
$newArray = array();
// Loop to combine buffer
foreach ($rows as $row) {
if (array_key_exists($row['id'], $newArray))
{
$newArray[$row['id']]['theory']['score1'] += $row['theory']['score1'];
$newArray[$row['id']]['theory']['score2'] += $row['theory']['score2'];
$newArray[$row['id']]['lab']['score1'] += $row['lab']['score1'];
$newArray[$row['id']]['lab']['score2'] += $row['lab']['score2'];
} else {
$newArray[$row['id']]['theory']['score1'] = $row['theory']['score1'];
$newArray[$row['id']]['theory']['score2'] = $row['theory']['score2'];
$newArray[$row['id']]['lab']['score1'] = $row['lab']['score1'];
$newArray[$row['id']]['lab']['score2'] = $row['lab']['score2'];
}
}
// Loop to show data
foreach ($newArray as $key => $value) {
echo $key." ".$value['theory']['score1']." ".$value['theory']['score2']." ".$value['lab']['score1']." ".$value['lab']['score2']."\n";
}
Output:
112 70 80 75 80
110 0 0 75 80
Let's say that you receive your data as Arrays:
$data=array();
$data[0]=[112,70,80,0,0];
$data[1]=[112,0,0,75,80];
$data[2]=[113,71,81,0,0];
$data[3]=[113,0,0,76,81];
If you know in advance that each ID will have exactly two records:
echo '<table>';
echo '<thead>';
echo '<tr>';
echo '<th rowspan="2">ID</th><th colspan="2">theory</th><th colspan="2">lab</th>';
echo '</tr>';
echo '<tr>';
echo '<th>score1</th><th>score2</th><th>score1</th><th>score2</th>';
echo '</tr>';
echo '</thead>';
echo '<tbody>';
for($i=0;$i<count($data);$i++)
{
$d=$data[$i];
echo '<tr>';
echo '<td>'.$d[0].'</td>'; //ID
echo '<td>'.$d[1].'</td><td>'.$d[2].'</td>';
$d=$data[++$i]; //take next element from array
echo '<td>'.$d[3].'</td><td>'.$d[4].'</td>';
echo '</tr>';
}
echo '</tbody>';
echo '</table>';
Code on PHPfiddle.
But generally, your SQL query should be changed in order to represent pivoted data and then you will not have this issue. However, you emphasized that this is out of your power.
i hava multidimensional array
<?php
$data = array(
array(
'name'=>'ahmed',
'job'=>'engineer',
'age'=>25,
'hobbies' => array('drawing','swimming','reading'),
'skills' => array('coding','fasting learning','teaching')
),
array(
'name'=>'Sara',
'job'=>'designer',
'age'=>19,
'skills'=>array('fast learning')
) ,
array(
'name'=>'Ali',
'age'=>25,
'city'=>'cairo'
),
array(
'name'=>'Hossam',
'job'=>'accountant',
'age'=>25,
'city'=>'zagazig'
),
array(
'name'=>'Esraa',
'job'=>'Designer',
'age'=>23,
'city'=>'zagazig',
'hobbies' => array('writing','reading'),
'skills' => array('coding','teaching')
),
);
i want count Arrays where city = "zagazig" or "cairo"
and echo Array Values
Example :
There is [ 1 ] people of City => [ cairo ] :
---------------- Result -----------------------
Name => Ali
Age => 25
City => cairo
if City !exist echo Values
Example :
*---------------- Invaild Data -------------
----------------------- First ---------------
Name => Sara
Job => designer
Age => 19
Skill => fast learning
----------------- Second ----------------
Name => ahmed
Job => engineer
Age => 25
-------------------- Hobbies ----------------
drawing
swimming
reading
-------------------- Skills ----------------
coding
fasting learning
teaching
but i don't know how to loop Multidimensional Array
Given that this is just a raw array, a simple if with foreach should suffice.
First, if the criteria is to get certain entries using city, just use a stripos to search;
$search_string = 'zagazig';
$results = array();
foreach($data as $value) {
if(
!empty($value['city']) &&
(stripos($value['city'], $search_string) !== false)
) {
$results[] = $value;
}
}
This checks if the entry has a city index, then just pushes that array inside a container $result. After gathering the results, just loop it like any normal array:
if(!empty($results)) {
echo 'Number of results: ' , count($results), '<br/> Result <hr/>';
foreach($results as $r) {
echo "
Name: {$r['name']}
Job: {$r['job']}
Age: {$r['age']} <br/>
";
echo !empty($r['hobbies']) ? '<br/>Hobbies: <br/>' . implode('<br/>', $r['hobbies']) : '';
}
}
Output
Of course you can use a <table> tag if you want, this is just an ugly example.
If you like something a little bit different, you can also use array_filter:
Here's an example of it (this also includes some searching inside hobbies and skills):
$search_string = 'coding';
$criteria = 'skills';
$results = array_filter($data, function($e) use ($search_string, $criteria) {
return (
!empty($e[$criteria]) &&
(!is_array($e[$criteria])
? (strpos($e[$criteria], $search_string) !== false)
: (in_array($search_string, $e[$criteria]))
)
);
});
Output
Use php foreach() like:
foreach (array_expression as $value)
{
statement
}
Foreach Documentation
TL;DR
I'm trying to loop all the rows and output it with html. When I'm looping it, I get an array with the properties and values of a single row which is also the last row, when I do not loop it, I get 2 arrays (each array is a row) within an array. For some reason it doesn't loop it and display all the rows as it should, how do I fix this?
I'm trying to make a loop of sections and the articles within them, where as each article has a parent section.
In the database, there are 5 sections and 2 articles, article #1 has section #1 as it's parent and article #2 has section #2 as it's parent.
When print it as an array without looping it, I get the following array;
Array
(
[0] => Array
(
[s_id] => 1
[s_name] => News
[s_slug] => news
[s_visibility] => 1
[s_type] => 1
[s_status] => 1
[s_permission] => 0
[s_external] => 0
[s_location] => news
[s_color] => 1
[s_homepage] => 1
[a_id] => 1
[a_section] => 1
[a_title] => Ted Cruz’s ‘Secret’ Skill That No President Has Likely Had Since Thomas Jefferson
[a_description] => Apparently Cruz, whose famed 2013 marathon filibuster speech over defunding Obamacare jumped across a range of topics, has an uncanny capability to remember things he hears verbatim.
[a_content] => Apparently Cruz, whose famed 2013 marathon filibuster speech over defunding Obamacare jumped across a range of topics, has an uncanny capability to remember things he hears verbatim.
[a_views] => 0
[a_visibility] => 1
[a_date] => 17.11.2015
[a_author] => 1632422528
[a_category] => 1
[a_slug] =>
)
[1] => Array
(
[s_id] => 2
[s_name] => VOD
[s_slug] => vod
[s_visibility] => 1
[s_type] => 2
[s_status] => 1
[s_permission] => 0
[s_external] => 0
[s_location] => vod
[s_color] => 2
[s_homepage] => 1
[a_id] => 2
[a_section] => 2
[a_title] => GTA V PC Edition Released
[a_description] => Wondering where the score is? Our GTA Online review will remain scoreless, as a score does not properly reflect its continuously changing nature. Here's how and why we decided to do it this way.
[a_content] => Wondering where the score is? Our GTA Online review will remain scoreless, as a score does not properly reflect its continuously changing nature. Here's how and why we decided to do it this way.
[a_views] => 0
[a_visibility] => 1
[a_date] => 19.11.2015
[a_author] => 1632422528
[a_category] => 1
[a_slug] =>
)
)
But when I run it into a foreach loop, it outputs only a single array which is the later one (1).
I'm using CodeIgniter 3, the loop is inside a library called "Global_functions",
The model is "Functions_model".
Global_functions (only the related function, not the entire class because it contains other unrelated functions):
public function get_homepage_sections()
{
$getHomeData = $this->CI->functions_model->get_homepage_data();
foreach ($getHomeData as $get_sections)
{
switch ($get_sections['s_color'])
{
case 1:
$sectionColor = "blue";
break;
case 2:
$sectionColor = "purple";
break;
case 3:
$sectionColor = "orange";
break;
case 4:
$sectionColor = "green";
break;
default:
$sectionColor = "";
break;
}
$outputData = '
<li>
<div><h2 class="category ' . $sectionColor . '">' . $get_sections['s_name'] . '</h2></div>';
$outputData .= '
</li>';
}
return $get_sections;
}
Functions_model;
public function get_homepage_data()
{
$selected_columns = array(
'sections.s_id',
'sections.s_name',
'sections.s_slug',
'sections.s_visibility',
'sections.s_type',
'sections.s_status',
'sections.s_permission',
'sections.s_external',
'sections.s_location',
'sections.s_color',
'sections.s_homepage',
'articles.a_id',
'articles.a_section',
'articles.a_title',
'articles.a_description',
'articles.a_content',
'articles.a_views',
'articles.a_visibility',
'articles.a_date',
'articles.a_author',
'articles.a_category',
'articles.a_slug'
);
$query = $this->db->select( $selected_columns )
->from( config_item('sections') . ', ' . config_item('articles') )
//->join( config_item('articles'), 'articles.a_section = sections.s_id' )
->where( 'articles.a_section = sections.s_id' )
//->or_where( 'user_email', $user_string )
->get();
if ( $query->num_rows() >= 1 )
{
return $query->result_array();
}
}
Being called from the controller as follows (homepageSection);
public function index()
{
/* if ($this->require_role('admin')) {
echo $this->load->view('examples/page_header', '', TRUE);
echo '<p>You are logged in!</p>';
echo $this->load->view('examples/page_footer', '', TRUE);
}*/
// return $isAutoRememberMe;
//extra_for_auth();
// Call a function of the model
$data['getGlobalMessage'] = $this->global_functions->get_global_message();
$data['userOptions'] = $this->global_functions->extra_for_auth();
$data['homepageSection'] = $this->global_functions->get_homepage_sections();
//print_r ($data);
$this->parser->parse('template/header', $data);
$this->parser->parse('sections/homepage', $data);
$this->load->view('template/footer');
}
section/homepage file contains the call {homepageSection}, as you can see the parser is called and parses the file rather than loading it with view().
I think there is an error in get_home_sections()
instead of:
return $get_sections;
you should:
return $getHomeData
you are returning the last item from the array, that looks like the problem you stated.
Another point i see a little bit confusing is the var you are cummulating html.
$outputData is being reset in each loop, and you are not doing nothing with it. It's a good idea to initialize it at the begining of the funcion as empty string
$outputData = '';
and in the loop you should do an additive assingment with .=
i m trying to build recursive menu using PHP but not succeeding
mysql table
menuid name parentid
and my php code
function generateMenubar()
{
$data = Yii::app()->db->createCommand("select * from menu");
$result = $data->queryAll();
$html = '<ul class = "navigation">';
foreach($result as $row)
{
if($row['parentid'] == "0")
{
$html .= '<li><span>'.$row["menuname"].'</span>';
$menu_id = $row['menuid'];
$html .= $this->generateHTML($result,$menu_id,$html);
}
}
return $html;
}
function generateHTML($result,$menu_id,$html)
{
foreach($result as $row_sub)
{
if($menu_id == $row_sub['parentid'])
{
$html .= '<ul><li><span>'.$row_sub['menuname'].'</span>';
$menu_id = $row_sub['menuid'];
$html .= $this->generateHTML($result,$menu_id,$html);
$html .= '</li>';
}
}
return $html.'</ui>';
}
but this loop is not stopping and generating wrong output. it can have sub levels upto n level. i want to make it dynamic cuz levels may change in future any suggestion ?
Your problem is that you do not have a structured result to iterate over. You might have SubElement 2 > 3 > 4 as your first result but 2 > 3 > 1 as your 5th Result. So you can't just iterate over the result once and build your html.
What you want to do (appart from, switching to nested sets, which is what you REALLY want to do wink) is structure your result first.
Iterate over your result and build a nested array to iterate over recusively to build your HTML. To find "where to put your element" in your recursive array you need to recursively check back with your existing array always as well. IF all you store is id and parent id, how to find out what the root element is before you checked ALL elements right?
So i could write the code to do so, but i rather do not because it would be a horrible solution anyway.
To do so more efficiently it would really help if you do not only store your parentid but a level as well.
Then you could store your elements in a two dimensional array storing all elements for each level and then recursively use that array. i.e.
$navigationTempArray = array();
foreach($fakeMySQLResult as $row)
{
if(!array_key_exists($row['level'], $navigationTempArray )) {
$navigationTempArray[$row['level']] = array();
}
if(!array_key_exists($row['parentid'], $navigationTempArray[$row['level']] )) {
$navigationTempArray[$row['level']][$row['parentid']] = array();
}
$navigationTempArray[$row['level']][$row['parentid']][] = $row;
}
now you have an array like this:
array (
0 => array(
'root' => array(
1 => array('title' => 'Start' ...)
2 => array('title' => 'Team' ...)
3 => array('title' => 'Projects' ...)
)
),
1 => array(
2 => array(
4 => array('title' => 'Development' ...)
5 => array('title' => 'Design' ...)
6 => array('title' => 'Sales' ...)
),
3 => array(
7 => array('title' => 'Mayhem' ...)
8 => array('title' => 'X' ...)
)
),
2 => array(
4 => array(
9 => array('title' => 'PHP' ...)
10 => array('title' => 'MySQL' ...)
)
)
)
Now you can iterate over this array recursively, solving every level for every item to infinity ;-)
function returnSubNavigation($id,$level,$fullNavigationArray) {
$html = '';
if(array_key_exists($level, $fullNavigationArray) && array_key_exists($id, $fullNavigationArray[$level])) {
$html .= '<ul>';
foreach($fullNavigationArray[$level][$id] as $subElement) {
$html .= '<li><span>'.$subElement["menuname"].'</span>';
$html .= returnSubNavigation($subElement['id'], $level+1, $fullNavigationArray);
$html .= '</li>';
}
$html .= '</ul>';
}
return $html;
}
echo returnSubNavigation('root', 0, $navigationTempArray);
Here is an online fiddle kind of thing that proves it works
Some people who do not want to use nested sets often store pathes rather than parent id's.
i.e.:
| id | path |
| 1 | 1 |
| 2 | 2 |
| 3 | 1.1 |
| 4 | 1.2 |
| 5 | 2.1 |
| 6 | 3 |
This is a lot easier (cheaper in terms of performance) to iterate over. You can sort it a lot easier. Still, it brings a lot of problems and restrictions.
This is what my array looks like.
(int) Year 1 => array(
'Department 1' => array(
'Sales' => '12345'
),
'Department 2' => array(
'Sales' => '12345'
),
),
(int) Year 2 => array(
'Department 1' => array(
'Sales' => '12345'
),
'Department 2' => array(
'Sales' => '12345'
),
)
I want to be able to create a table where the headers are the Years on the X axis.
The Y axis needs to start with the Department name. The adjoining cells need to have sales, revenue, and total in one cell.
It should look like this...
Department____| ___YEAR1_______ | __Year2
Department 1 |Sales [dept 1][year 1] | Sales[dept 1][year 2]
Department 2 |Sales [dept 2][year 1] | Sales [dept 2][year 2]
I used nested foreach loops
foreach($List as $key=>$row) {
echo "<tr><td>".$key."</td>";
foreach($row as $key2=>$col){
echo "<td>" . 'Sales: '.round($col['sales'],2) ."</td>";
}
echo "</tr>";
}
echo "</table>"; ?>
but it printed the table with departments names on top on the x axis and years on the y axis. How do I get years on the x axis and departments on the y axis.
The problem is that the dimensions of your array don't correspond with the order that you want to iterate through them for your table. You need to pull out the keys explicitly to iterate through them in the nested loops.
$years = array_keys($List);
// Print column headings
echo "<table><thead><tr><th>Department</th>";
foreach ($years as $year) {
echo "<th>$year</th>";
}
echo "</tr></thead>";
// Print data rows
echo "<tbody>"
foreach (array_keys($List[$years[0]]) as $dept) {
echo "<tr><th>$dept</th>";
foreach ($years as $year) {
echo "<td>{$List[$year][$dept]['Sales'}]</td>";
}
echo "</tr>";
}
echo "</tbody></table>";
As I mentioned, this depends on all years having the same departments. If you add new departments over time, it won't work. You can fix this by using array_reduce to merge all the department lists, I'll leave that as an exercise for the reader.