foreach for groups and subgroups in php - php

i have table in database:
Group:
| id | Category | title |
| 1 | 1 | group1 |
| 2 | 2 | group2 |
| 3 | 1 | group3 |
| 4 | 3 | group4 |
| 5 | 2 | group5 |
| 6 | 1 | group6 |
News:
| id | Group | title | body |
| 1 | 3 | title1 | body1 |
| 2 | 2 | title2 | body2 |
| 3 | 1 | title3 | body3 |
| 4 | 4 | title4 | body4 |
| 5 | 1 | title5 | body5 |
| 6 | 5 | title6 | body6 |
| 7 | 3 | title7 | body7 |
| 8 | 2 | title8 | body8 |
| 9 | 1 | title9 | body9 |
| 10 | 6 | title10| body10 |
| 11 | 1 | title11| body11 |
| 12 | 5 | title12| body12 |
how can i show this as:
-GROUP1, GROUP3 and GROUP6
//GROUP1 (category1)
--title3
--title5
--title9
//GROUP3 (category1)
--title1
--title7
//GROUP6 (category1)
--title10
-GROUP2 and GROUP5
//GROUP2 (category2)
--title2
--title8
//GROUP5 (category2)
--title6
--titl12
-GROUP4
//GROUP4 (category3)
--title4
i will make this in foreach. thanks for help!

Your exact requested output makes this complicated.
$sql = 'SELECT n.title, n.Group AS group_id, g.Category AS cat_id
FROM News AS n
JOIN Group AS g ON g.id = group_id
ORDER BY cat_id, group_id, n.id';
$result = mysql_query($query);
$categories = array();
while ($row = mysql_fetch_assoc($result)) {
$catID = $row['cat_id'];
$groupID = $row['group_id'];
$title = $row['title'];
$categories[$catID]['groups'][$groupID]['titles'][] = $title;
}
foreach ($categories as $catID => $groups) {
$catGroups = '-GROUP'.implode(', GROUP',array_keys($groups)).PHP_EOL;
$lastComma = strrpos($catGroups,',');
if ($lastComma !== false) {
$catGroups = substr($catGroups,0,$lastComma-1).
' AND ' .substr($catGroups,$lastComma+1);
}
echo $catGroups;
foreach ($groups as $groupID => $titles) {
echo "//GROUP$groupID (category$catID)".PHP_EOL;
foreach ($groups as $group => $titles) {
echo '--'.$title.PHP_EOL;
}
}
}
If you didn't need such fancy output, this would be much simpler.
$sql = 'SELECT n.title, n.Group AS group_id, g.Category AS cat_id
FROM News AS n
JOIN Group AS g ON g.id = group_id
ORDER BY cat_id, group_id, n.id';
$result = mysql_query($query);
$lastCatID = null;
$lastGroupID = null;
while ($row = mysql_fetch_assoc($result)) {
$catID = $row['cat_id'];
$groupID = $row['group_id'];
$title = $row['title'];
if ($catID !== $lastCatID){
echo "*** CATEGORY $catID\n";
$lastCatID = $catID;
}
if ($groupID !== $lastGroupID){
echo "GROUP $groupID\n";
$lastGroupID = $groupID;
}
echo "-- $title\n";
}

You told, you have your values in the database. So you have to get them first, e.g. with the following database query:
SELECT
g.`title` AS `group_title`
, n.`title` AS `news_title`
FROM
`Group` AS g
INNER JOIN
`News` AS n
ON
g.`id` = n.`Group`
ORDER BY
g.`Category`
, n.`Group`
, n.`title`
Store the data in an array. Now you can use a foreach loop to iterate over the array.
===
Here my update:
First fill the array while reading from the database (example query see above).
<?php
$data = array();
$res = mysql_query('SELECT ...');
while (($row = mysql_fetch_assoc($res)) !== false) {
$data[$row['group_title']][] = $row['news_title'];
}
?>
Then write the array to the screen:
<?php
foreach ($data as $group_title => $groups) {
echo $group_title . "\n";
foreach ($groups as $news) {
echo "\t" . $news . "\n";
}
}
?>

Related

Generate JSON booleans from Db

I need to generate a JSON String using this format:
{"content":{"brands":1},"brands":[{"id":"1","name":"brand 1","description":"description","icon":"icon","url":"example.com","categories":{"1":"true","2":"true","3":"false","4":"false","5":"false","6":"false"}},{"id":"2","name":"brand2","description":"description","icon":"icon","url":"example.com","categories":{"1":"true","2":"true","3":"false","4":"false","5":"false","6":"false"}}]}
From this tables:
brands:
| id | name | description | icon | url |
|----|--------|-------------|------|-----|
| 1 | name 1 | description | icon | url |
| 2 | name 2 | description | icon | url |
| 3 | name 3 | description | icon | url |
| 4 | name 4 | description | icon | url |
| 5 | name 5 | description | icon | url |
| 6 | name 6 | description | icon | url |
categories:
| id | name | description | icon | url |
|----|--------|-------------|------|-----|
| 1 | name 1 | description | icon | url |
| 2 | name 2 | description | icon | url |
| 3 | name 3 | description | icon | url |
| 4 | name 4 | description | icon | url |
| 5 | name 5 | description | icon | url |
| 6 | name 6 | description | icon | url |
objects:
| id | id_brand | id_category |name | description | icon | url |
|----|----------|-------------|-------|-------------|------|-----|
| 1 | 1 | 1 |name 1 | description | icon | url |
| 2 | 1 | 2 |name 2 | description | icon | url |
| 3 | 2 | 1 |name 3 | description | icon | url |
| 4 | 2 | 2 |name 4 | description | icon | url |
this is my relevant code so far
public function actionBrand($id = null) {
if (empty($id)) {
// Obtiene datos de la base
$sql = "SELECT DISTINCT objects.id_brand AS id, brands.name AS name, brands.description AS description, brands.icon AS icon, brands.url AS url, objects.id_category, categories.name AS category " .
"FROM objects " .
"LEFT JOIN brands ON objects.id_brand = brands.id " .
"LEFT JOIN categories ON objects.id_category = categories.id " .
"ORDER BY objects.id_brand, objects.id_category ";
} else {
// Obtiene datos de la base
$sql = "SELECT DISTINCT objects.id_brand AS id, brands.name AS name, brands.description AS description, brands.icon AS icon, brands.url AS url, objects.id_category, categories.name AS category " .
"FROM objects " .
"LEFT JOIN brands ON objects.id_brand = brands.id " .
"LEFT JOIN categories ON objects.id_category = categories.id " .
"WHERE brands.id = " . (int) $id . " " .
"ORDER BY objects.id_brand, objects.id_category ";
}
$data = Yii::$app->db->createCommand($sql)
->queryAll();
// Obtiene categorias
$categories = Yii::$app->db->createCommand('SELECT id FROM categories ORDER BY id')
->queryAll();
if (!empty($data)) {
// Construye primer registro
$brands[0]['id'] = $data[0]['id'];
$brands[0]['name'] = $data[0]['name'];
$brands[0]['description'] = $data[0]['description'];
$brands[0]['icon'] = $data[0]['icon'];
$brands[0]['url'] = $data[0]['url'];
$total = count($data);
for ($i = 1, $j = 0; $i < $total; $i++) {
if ($brands[$j]['id'] == $data[$i]['id']) {
continue;
} else {
$j++;
$brands[$j]['id'] = $data[$i]['id'];
$brands[$j]['name'] = $data[$i]['name'];
$brands[$j]['description'] = $data[$i]['description'];
$brands[$j]['icon'] = $data[$i]['icon'];
$brands[$j]['url'] = $data[$i]['url'];
}
}
} else {
$brands = array();
}
// Construye y envia JSON
$json['content']['brands'] = count($brands);
$json['brands'] = $brands;
echo json_encode($json);
}
It generates the first part of the JSON that i need, but im stuck at the categories part i need to select the data from the base and convert it to id : (true)(false) on each brand
{"content":{"brands":1},"brands":[{"id":"1","name":"brand 1","description":"description","icon":"icon","url":"example.com"},{"id":"2","name":"brand2","description":"description","icon":"icon","url":"example.com"}]}
Can you help me?
Regards
After you are done building the brands, loop on the categories, searching brands for the existing id match. If it matches, then adjust a true false value for the categories. Then when the categories are completed, append them to every brand in a final loop.
$cleancats = [];
foreach ($categories as $cat) {
$result = false;
foreach($brands as $brand) {
if ($cat['id'] == $brand['id']) {
$result = true; break;
}
}
$cleancats[ $cat['id'] ] = $result;
}
array_walk ($brands,function(&$brand) use ($cleancats) {
$brand['categories'] = $cleancats;
});
(note put this after your for ($i = 1, $j = 0; $i < $total; $i++) loop ends)
That should get the categories to every brand in brands, as you would like.
If you need the categories to be a LITERAL "true" and "false" then adjust this one line above:
$cleancats[ $cat['id'] ] = ($result?'true':'false');

Count number of users for the comma separated values

I have comma-separated field base_users in my database. How do I query to count the totaluser of that group? I have no problem to calculate the totaluser if the data is not in comma-separated field.
SELECT COUNT(base_u_id) AS totaluser
FROM base_users
WHERE base_u_group =".$row['base_gp_id']."
1)base_users
|base_u_id | base_u_name | base_u_group |
------------------------------------------
| 1 | username1 | 1, 2, 4 |
| 2 | username2 | 3 |
| 3 | username3 | 3, 4 |
| 4 | username4 | 1, 4 |
2)base_groups
| base_gp_id | base_gp_name |
------------------------------
| 1 | group1 |
| 2 | group2 |
| 3 | group3 |
| 4 | group4 |
| 5 | group5 |
From the sample database above, my expected result will be:
Total User of group1 = 2
Total User of group2 = 1
Total User of group3 = 2
Total User of group4 = 3
Total User of group5 = 0
This is what I have tried so far:
<?php
$getUser = base_executeSQL("SELECT * FROM base_users");
while($row_getUser = base_fetch_array($getUser))
{
$explodeData = explode(", ",$row_getUser['base_u_group']);
foreach($explodeData as $data)
{
$getUserGroupSQL = base_executeSQL("SELECT COUNT(base_u_id) AS totaluser FROM base_users as user, base_groups as gp WHERE gp.base_gp_id ='".$data."' ");
while($UserGroupProfile_row = base_fetch_array($getUserGroupSQL))
if (base_num_rows($getUserGroupSQL)!= 0)
$totaluser = $UserGroupProfile_row["totaluser"];
elseif (base_num_rows($getUserGroupSQL)== 0)
$totaluser = 0;
}
}
?>
Use below logic: Just HINT
$group = array(1=>0,2=>0,3=>0,4=>0,5=>0);
$base_u_group = array('1,2,4','3','3,4','1,4');
foreach($base_u_group as $gr) {
$split = explode(',', $gr);
if (!empty($split)) {
foreach($split as $val) {
if ($val) {
$group[$val] = $group[$val] + 1;
}
}
}
}
var_dump($group);
Try this:
SELECT COUNT(u.base_u_id), g.base_gp_name FROM base_users u
INNER JOIN base_groups g ON IF(POSITION(',' IN u.base_u_group) > 0, u.base_u_group LIKE ('".$row['base_gp_id'].",%') OR u.base_u_group LIKE ('%, ".$row['base_gp_id'].",%') OR u.base_u_group LIKE ('%, ".$row['base_gp_id']."'), u.base_u_group = '".$row['base_gp_id']."')
WHERE g.base_gp_id = ".$row['base_gp_id']."

PHP MySQL code optimize

Is there any MySQL function that will optimize this code? A child ID getting all parent ID
function get_parents() {
$ids = array();
while($id) :
$query = "SELECT placement_id FROM referrals WHERE user_id = $id";
$query = $this->db->query($query);
$result = $query->row();
if(!isset($result->placement_id)) :
break;
elseif(isset($result->placement_id) && $result->placement_id == 2) :
break;
endif;
$id = $result->placement_id;
array_push($ids, $id);
if($result) :
continue;
endif;
break;
endwhile;
return $ids;
}
The code above will return all parent ID of given user_id, this will stop if nothing is found. I found this code too slow and heavy load.
My Table
relations table
| id | user_id | placement_id |
| 1 | 2 | NULL |
| 2 | 3 | 2 |
| 3 | 4 | 2 |
| 4 | 5 | 3 |
| 5 | 6 | 4 |
| 6 | 7 | 3 |
| 7 | 8 | 3 |
| 8 | 9 | 3 |
| 9 | 10 | 6 |
| 10 | 11 | 5 |
| 11 | 12 | 6 |
| 12 | 13 | 4 |
| 13 | 14 | 3 |
| 14 | 15 | 9 |
| 15 | 16 | 10 |
user_id is the child and parent is placement_id
You can rewrite you code as:
function get_parents() {
$ids = array();
while($id){
$query = "SELECT placement_id FROM referrals WHERE user_id = $id";
$query = $this->db->query($query);
$result = $query->row();
if(isset($result->placement_id) && $result->placement_id !== 2)
{
$id = $result->placement_id;
array_push($ids, $id);
}
}
return $ids;
}
It excludes some additional function calls such continue,break etc. Also, Make sure you have INT as type of user_id with indexing on this column.
I would personally do something like this:
<?php
define('MAX_NEST_DEPTH', 15);
function get_parent($child_id) {
$child_id = (int) $child_id;
$parents = array();
$counter = 0;
do {
$sql = "SELECT placement_id
FROM referrals
WHERE user_id = {$child_id}";
$query = $this->db->query($query);
$result = $query->row();
$child_id = (int) $result->placement_id;
$parent[] = $child_id;
$counter++;
}
while ($child_id != 0 || $counter == MAX_NEST_DEPTH);
return $parents;
}
You wont get around the query in a loop here, mysql does not support n-level-nested SELECT, otherwise we could just do it in one go.

How to count the total of each group categorize by set from mysql

I may not use the proper subject of the problem. But here's the detail. I've got 3 tables of data 2 of them are set name and group name. The rest is data - user db. Here's the db.
set_name
+--------+-----------+
| set_id | set_title |
+--------+-----------+
| 1 | Set A |
+--------+-----------+
| 2 | Set B |
+--------+-----------+
group_db
+--------+-----------+--------+
| grp_id | grp_title | set_id |
+--------+-----------+--------+
| 1 | Grp. A | 1 |
+--------+-----------+--------+
| 2 | Grp. B | 1 |
+--------+-----------+--------+
| 3 | Grp. C | 1 |
+--------+-----------+--------+
| 4 | Grp. D | 1 |
+--------+-----------+--------+
| 5 | Grp. E | 1 |
+--------+-----------+--------+
| 6 | Grp. F | 2 |
+--------+-----------+--------+
user_db
+--------+-----------+
| usr_id | grp_id |
+--------+-----------+
| 1 | 1 |
+--------+-----------+
| 2 | 1 |
+--------+-----------+
| 3 | 2 |
+--------+-----------+
| 4 | 1 |
+--------+-----------+
| 5 | 3 |
+--------+-----------+
| 6 | 4 |
+--------+-----------+
| 7 | 5 |
+--------+-----------+
| 8 | 5 |
+--------+-----------+
| 9 | 5 |
+--------+-----------+
| 10 | 6 |
+--------+-----------+
According to the information provided above. I expect a summary table in which count all user and categorize by group and set. For example:
+-----+--------------------------------------------+--------+
| SET | Set A. | Set B. |
+-----+--------------------------------------------+--------+
|GROUP| Grp. A | Grp. B | Grp. C | Grp. D | Grp. E | Grp. F |
+-----+--------------------------------------------+--------+
| NUM | 3 | 1 | 1 | 1 | 3 | 1 |
+-----+--------------------------------------------+--------+
|TOTAL| 9 | 1 |
+-----+--------------------------------------------+--------+
And this is how I do.
<table>
<tr>
<?
$sql_set=mysqli_query($con,"SELECT *,count(group_db.grp_id) AS nGrp\n"
. "FROM set_name\n"
. "INNER JOIN group_db ON set_name.set_id=group_db.set_id\n"
. "GROUP BY set_name.set_id\n"
. "ORDER BY set_name.set_id asc");
echo "<td>SET</td>";
while($rec_set=mysqli_fetch_array($sql_set)){
echo "<td colspan=\"$rec_set[nGrp]\">$rec_set[set_title]</td>";
}
?>
</tr>
<tr>
<?
$sql_sGrp=mysqli_query($con,"SELECT * from group_db\n"
. "WHERE set_id='$rec_set[set_id]'\n"
. "ORDER BY grp_title asc");
echo "<td>GROUP</td>";
while($rec_sGrp=mysqli_fetch_array($sql_sGrp)){
echo "<td>$rec_sGrp[grp_title]</td>";
}
?>
</tr>
</table>
That's it. I don't know how to go further. Please be advice.
Ps. Should I make them all in multilevel array to make it easier?
I would do something like:
SELECT
*
FROM
user_db u
JOIN
group_db g ON u.grp_id = g.grp_id
JOIN
set_name s ON g.set_id = s.set_id
(EDIT: changed qry to this ^ which can be seen here: http://sqlfiddle.com/#!2/e749f/4)
And then in PHP:
$newArray = array();
while($rec_set=mysqli_fetch_array($sql_set)){
$newArray[$rec_set['set_title']][$rec_set['grp_title']] += 1;
}
which should give you a nice multidimensional array of the results that you can parse through however you want
And to give a table that looks like:
+-----+--------------------------------------------+--------+
| SET | Set A. | Set B. |
+-----+--------------------------------------------+--------+
|GROUP| Grp. A | Grp. B | Grp. C | Grp. D | Grp. E | Grp. F |
+-----+--------------------------------------------+--------+
| NUM | 3 | 1 | 1 | 1 | 3 | 1 |
+-----+--------------------------------------------+--------+
|TOTAL| 9 | 1 |
+-----+--------------------------------------------+--------+
I would use:
<tr>
<td>SET</td>
<?php foreach($newArray as $set => $group): ?>
<td colspan="<?=count($newArray[$set])?>"><?=$set?></td>
<?php endforeach; ?>
</tr>
<tr>
<td>GROUP</td>
<?php foreach($newArray as $set => $group): ?>
<?php foreach($group as $group_name => $amount): ?>
<td><?=$group_name?></td>
<?php endforeach; ?>
<?php endforeach; ?>
</tr>
<tr>
<td>NUMBER</td>
<?php foreach($newArray as $set => $group): ?>
<?php foreach($group as $group_name => $amount): ?>
<td><?=$amount?></td>
<?php $totals[$set] += $amount;?>
<?php endforeach; ?>
<?php endforeach; ?>
</tr>
<tr>
<td>TOTAL</td>
<?php foreach($newArray as $set => $group): ?>
<td colspan="<?=count($newArray[$set])?>"><?=$totals[$set]?></td>
<?php endforeach; ?>
</tr>
However, now that I look at how you would actually display it, if you really wanted a table that looked like you put, then a multidimensional array would probably not be the best way to loop through your data since all these loops are UGLY! (And it does not scale too well horizontally as you add more and more sets and groups). I did not check it for accuracy.
echo '<table>';
$rows = array('SET', 'GROUP', 'NUM', 'TOTAL');
$setids = array();
$grp_usercounts = array();
$set_usertotals = array();
foreach($rows as $key => $row){
echo "<tr> $rows </td>";
switch ($key){
case 0: //SET
$sql = "SELECT s.set_id, set_title, count(g.grp_id) nGrp
FROM set_name s
JOIN group_db g ON s.set_id = g.set_id
group by set_id";
$sql_set = mysqli_query($con, $sql);
while($rec_set=mysqli_fetch_array($sql_set)){
echo '<td colspan="'.$rec_set['nGrp'].'">'. rec_set['set_title'].'</td>';
$setids[$rec_set['set_id']] = $rec_set['nGrp'];
}
break;
case 1://GROUP
foreach($setids as $setid => $val){
$sql = "SELECT g.grp_id, grp_title, count(usr_id) nUsr
FROM group_db g
JOIN user_db u ON u.grp_id = g.grp_id
where set_id = $setid
group by g.grp_id order by grp_title";
$sql_set = mysqli_query($con, $sql);
$total = 0;
while($rec_set=mysqli_fetch_array($sql_set)){
echo '<td>'. $rec_set['grp_title'].'</td>';
$grp_usercounts[$rec_set['grp_id']] = $rec_set['nUsr'];
$total += $rec_set['nUsr'];
}
$set_usertotals[$setid] = $total;
}
break;
case 2://NUM
foreach($grp_usercounts as $key => $grp_usercount){
echo '<td>'. $grp_usercount .'</td>';
}
break;
case 3: //TOTAL
foreach($set_usertotals as $setid => $set_usertotal){
echo '<td colspan="'.$setids[$setid].'">'. $set_usertotal .'</td>';
}
break;
}
}
unset($setids);
unset($grp_usercounts);
unset($set_usertotals);
echo '</table>';

PHP and MySQL, array associated with 2 keys

I have this scenario.
I input $groupid="1";
main table
----------------------
| groupid | postid |
|---------------------|
| 1 | 1 |
| 2 | 2 |
| 1 | 3 |
$query = "SELECT postid FROM `mainl` WHERE groupid='$groupid'";
$result = mysql_query($query);
// a group of postids belonging to that groupid which should hold [1, 3] for groupid=1
while($row = mysql_fetch_array($result)) {
$postids[] = $row["postid"];
}
second table
-------------------------------------------
| postid | commentid | comment |
-------------------------------------------
| 1 | 1 | testing 1 |
| 1 | 2 | testing 2 |
| 1 | 3 | what? |
| 2 | 1 | hello |
| 2 | 2 | hello world |
| 3 | 1 | test 3 |
| 3 | 2 | begin |
| 3 | 3 | why? |
| 3 | 4 | shows |
$query = "SELECT * FROM `second`";
$result = mysql_query($query);
while ($row = mysql_fetch_array($result)) {
if (in_array($row["postid"], $postids)) {
$comments[$row["postid"]] = $row["comment"];
But how should I take care of commented
I want the postid array to be [1,3] and my comment array to be
[commentid: comment] [1:testing1, 2: testing2, 3: what?] for postid=1
and
[1:test3, 2:begin, 3: why? 4:shows] for postid=3
how should be arrange everything such comment are associated with commentid and postid?
First I would follow rokdd suggestion and make 1 query
SELECT m.groupid , s.postid, s.commentid, s.comment FROM `main1` m JOIN `second` s USING (postid) where m.groupid = 1
Then I would make a multi-dimensional array
while ($row = mysql_fetch_array($result))
$groups[$row['groupid'][$row['postid']][$row['commentid']=$row['comment'];
then to iterate through the array
foreach($groups as $group)
foreach($group as $post)
foreach($post as $comment)
echo $comment;
This will keep track of groups also (if you ever want to select by more than 1 group.
If you don't care about groups just drop off the first part of the array.
while ($row = mysql_fetch_array($result))
$posts[$row['postid']][$row['commentid']=$row['comment'];
foreach($posts as $post)
foreach($post as $comment)
echo $comment;
I guess to use the join in sql so that you will have one statement:
SELECT * FROM second as second_tab LEFT join main as main_table ON main_table.post_id=second_table.post_id WHERE main_table.group_id="3"
Well not tested now but thats a way to solve some of your problems!

Categories