so i have a question regarding, hmmm filtering data in mysql/php.
So i have table lets say
ID | fk1 | fk2
1 1 1
2 1 2
3 1 3
4 2 1
5 2 2
6 3 3
Basicaly i have in same table many occurancies of fk1 that are referenced to fk2 and when i output that in table ofcourse i get result as
1 1
1 2
1 3
2 1
etc. And that is normal. What i want to do is basically output one time FK2 value lets say 1, and all corresponding FK1 values below it. Sorta like group by but for each occurancie of FK2 i need all the FK1s that have that FK2 in their row.
I managed to get it working somehow so that all FK1 print out and corresponding FK2 but other way around wont work :S
$FK1 = '';
while($row = mysql_fetch_array($result_set)){
if($FK1 != $row['fk1']){
if($FK1 != ''){
echo $printout;
}
$FK1 = $row['fk1'];
$printout = "<tr class='success'><td>" . "<strong>" . $row['fk1']. "</td></tr>";
}
$printout = $printout .'<td class="warning"> '.$row['fk2']. '</td></tr>';
}
echo $printout ;
Any idea how to do this with some smart loop instead of using multiple queries on base?
Thanks
For each iteration of the loop that prints the query, you can check if the previous iteration printed the same thing and (if yes) skip the printing or print the current one if not.
I hope I understood the question and my answer is clear enough.
Something like this:
$cFk1 = "";
foreach($query_result as $cVal){
if($cVal != cFk1){
print $cVal;
}
$cFk1 = $cVal;
}
You can try GROUP_CONCAT in your query such as:
SELECT
fk2, GROUP_CONCAT(fk1) fk1,
FROM
table
GROUP BY
fk2
And then in your PHP code:
foreach($rows as $row) {
// plain echo
echo $row['fk2'].' '.$row['fk1'];
}
or
foreach($rows as $row) {
// or with post-processing
echo $row['fk2'].' ';
$fk1 = explode(',', $row['fk1']);
foreach($fk1 as $value) {
echo $value.'-';
}
}
But beware - GROUP_CONCAT has its limits, you should make sure the strings don't contain the separator (if it's only numbers, it's ok), etc.
Related
i have this code to generate a report joining two table.
$agebracket= $_POST['age_bracket']; //coming from dropdown list
$sql=mysql_query("select qshortcode from question_details where pans1 like '%$agebracket%'");
while($row=mysql_fetch_array($sql)){
$utility[] = preg_replace('/[0-9]+/','',$row['qshortcode']);
}
$slno=0;
for($i=0;$i<count($utility);$i++) {
$last=""; //as suggested
$check=mysql_query("select q.qshortcode,q.qcode,q.question,p.paid_rev from question_details q left outer join paid_response p on q.qcode=p.qno where q.qshortcode like '$utility[$i]%' group by q.qcode");
while($qscode=mysql_fetch_array($check)) {
if($last =substr($qscode['qcode'],strlen($last))) {
$last = $qscode['qcode'];
$slno++;
$slid = $slno ;
} else {
$slid .= ".1";
}
echo "<tr>";
echo "<td>".$slid.' '."</td>";
echo "<td>".$qscode['qshortcode'].' '."</td>";
echo "<td>".$qscode['qcode'].' '."</td>";
echo "<td>".$qscode['question'].' '."</td>";
echo "<td>".$qscode['paid_rev']."<br></td>";
echo "</tr>";
}
}
echo "</table>";
this generates this report fetching from two tables with left outer join to also get the blank revenue
SL-No Qcode Question Revenue
1 test whatever
1.1 test_1 zzz
2 test_2 xxx something //here it is becoming 2 but it should be 1.1.1
3 abc vvv
3.1 abc1 khkhk something
now actually i want to auto-increment SL-No with 1 then if qcode matches like the 1st row qcode it will be 1.1 then 1.1.1 then when it dont matches it will be 2. like the report will be like
SL-No Qcode Question Revenue
1 test whatever
1.1 test_1 zzz
1.1.1 test_2 xxx something
2 abc vvv
2.1 abc1 khkhk something
I would do something like this (untested code):
$slno=0;
[...] // for loop omitted, just starting at 0 instead of 1, to increment properly after.
$last="-1"; // To avoid comparing two empty lines at first pass, which will obvisouly be alway true, sorry.
while ([mysql query ....]) {
if ($last != substr($qscode['qcode'],0, strlen($last))) {
$last = $qscode['qcode'];
$slno++;
$slid = strval($slno)
} else {
$slid .= ".1"
}
echo "<tr>";
echo "<td>".$slid.' '."</td>";
echo "<td>".$qscode['qshortcode'].' '."</td>";
[...] // rest omitted
}
I have a mysql database called menus. I am able to query my database to obtain a recordset accordingly. I do NOT want to write a query for each season. My problem: I want to write a php if statement within body to echo a message if the season field CONTAINS 2.
table menu
id | item (varcar) | season (set)
1 | fresh lemonade | 2,3
2 | smoothie | 2
3 | cafe latte | 4
My query works fine
mysql_select_db($database_rest, $rest); $query_menus = "SELECT * FROM
menus";
$menus = mysql_query($query_menus, $rest) or die(mysql_error());
$row_menus = mysql_fetch_assoc($menus);
$totalRows_menus = mysql_num_rows($menus);
I can write a php if to work where recordset field = 2 that works.
<?php echo $row_menus['item']; ?>: <?php
if (#$row_menus['season'] == 1)
{
echo "Winter";
}
else if (#$row_menus['season'] == 2)
{
echo "Spring";
}
else if (#$row_menus['season'] == 3)
{
echo "Summer";
}
else if (#$row_menus['season'] == 4)
{
echo "Fall";
}
?>
Result Shows:
fresh lemonade: Spring
smoothie: Spring
cafe latte: Fall
I want to write php so that if season CONTAINS 2 (example: if (#$row_menus['season'] CONTAINS 1) echo Spring, etc for each. so that result would look like this:
fresh lemonade: Spring
fresh lemonade: Summer
smoothie: Spring
cafe latte: Fall
First of all, it's time to upgrade those mysql_* functions! Second, there's better ways to set up the relationship between the item and its seasons. However, I'll let you look into that stuff.
$query_menus = "SELECT * FROM menus";
$menus = mysql_query($query_menus, $rest) or die(mysql_error());
$seasons_array = array('All Seasons', 'Winter', 'Spring', 'Summer', 'Fall');
while($row_menus = mysql_fetch_array($menus))
{
$item = $row_menus['item'];
$season = $row_menus['season'];
if(strpos($season, ',') !== false)
{
$seasons = explode(',', $season);
// To show the item and season on separate rows
foreach($seasons as $s)
echo $item . ': ' . trim($seasons_array[(int)$s]);
// To show the item, and then a list of seasons
echo $item . ': ';
foreach($season as $k => $s)
echo trim($seasons_array[(int)$s]) . (($k + 1) == count($season) ? '' : ', ');
}
else
{
echo $item . ': ' . $seasons_array[(int)$season];
}
}
I didn't test this, but it should work for you. Try it out, and let us know.
EDIT: I updated it so that you can list the items on separate rows, or list the item followed by each season.
You have two choices:
use PHP to split the field into an array and work through that
use multiple rows where season only holds one value
Using PHP, you could use $season=explode(',',$row_menus['season']); and then use a foreach statement to iterate through $season
The problem you have is that PHP interprets 2,3 as a string. When it's converted into a number, it appears as 2
Try using multiple rows for the season field:
id | item (varcar) | season
1 | fresh lemonade | 3
2 | smoothie | 2
3 | cafe latte | 4
4 | fresh lemonade | 2
This will also help where you want to select all rows where season=2
Finally, as Tobias said, don't use the mysql_ functions. Use newer functions which are supported
I have e.g. the following data returned from a query, each name is an item:
id name comment
1 FF hey
1 FF hey back!
2 LL
3 PP i think its great!
3 PP me too
3 PP I'm not sure
4 TT
5 II
6 KK yesterday is the new tomorrow
When I display it, each 'item' has an id and are displayed in DIVs use LI.
As you can see though there are multiple comments sometimes for an 'item', each on a separate line
What I want to do is display each item and then show comments under each item if there are any. So, i can't group by anything at query stage as the comment section is unique, but need to group at display stage
So currently have:
while ($row = mysql_fetch_array($result)){
echo '<li><div class=className><div class=itemName>'.$row[name].'</div>';
if($row[comment]){
echo '<div class=newRow>'.$row[comment].'</div>';
}
echo '</div></li>';
}
Now, this is no good because this will produce multiple displays for the same item with one comment under each.
Can I do this or should I bring in the data differently?
The ideal result is e.g.
FF LL PP etc etc etc
hey i think its great!
hey back! me too
I'm not sure
You can use GROUP_CONCAT() on your mysql query to group all the comments together for each name
SELECT id, name
GROUP_CONCAT(comment) AS comment
FROM table
GROUP BY name;
then explode() the $row[comment] in your php code
while ($row = mysql_fetch_array($result)){
echo '<li><div class=className><div class=itemName>'.$row['name'].'</div>';
if($row['comment'] != ""){
$comments = explode(",",$row['comment']);
foreach($comments as $comment){
echo '<div class=newRow>'.$comment.'</div>';
}
}
echo '</div></li>';
}
Edit
Thanks to #CBroe, I now know that GROUP_CONCAT() has a group_concat_max_len default of 1024. You will want to increase this before running the GROUP_CONCAT() query -
SET [GLOBAL | SESSION] group_concat_max_len = 10240; // must be in multiples of 1024
SELECT id, name
GROUP_CONCAT(comment) AS comment
FROM table
GROUP BY name;
you will also need to be aware of max_allowed_packet as this is the limit you can set var_group_concat_max_len to.
note: mysql_query() does not allow multiple queries, so you will need to do 2 mysql_query(), and you can use SET SESSION ... so that all queries in your current session have that max_len. It would be better to change from mysql_ functions (which are depreciated) and change to mysqli_ or PDO as they offer multiple query option. also check out - http://php.net/manual/en/mysqlinfo.api.choosing.php
Don't confuse data access with output and you will have an easier time attacking this sort of problem.
//Fetch and Sort
$data = array();
while ($row = mysql_fetch_array($result)){
$item = $row['item'];
if(!isset($data[$item]) {
$data[$item] = array():
}
$data[ = $data[$item][] = $row['comment'];
}
//Output
foreach($data as $item => $comments) {
echo '<li><div class=className><div class=itemName>'.$item.'</div>';
foreach($comments as $comment) {
echo '<div class=newRow>'.$comment.'</div>';
}
echo '</div></li>';
}
If you are not getting the data back sorted by id already, add to the end of your query:
ORDER BY name
which will retrieve the same list ordered by id. Then in your while loop, add a variable that keeps track of the last item name that you saw. If it changes, add a new li, otherwise, add the comment on to the end of your current list.
Say I have a query the following query run:
Edit
Added order clause because the real sql statement has one.
SELECT description, amount, id FROM table ORDER BY id
In this instance, the ID is not unique to the dataset. It would return something like this.
Description Amount ID
----------- ------ --
1 Hats 45 1
2 Pants 16 1
3 Shoes 3 1
4 Dogs 5 2
5 Cats 6 2
6 Waffles 99 3
What I need to do is enclose each section of IDs in it's own div (So rows 1,2,3 in one div, 4,5 in another div and 6 in it's own div).
There are tons of solutions to this but I just can't think of one that isn't overly complicated.
I want to be able to keep the SQL how it is and somehow sort the data set in PHP so that I can loop through each section of the dataset while looping through the dataset as a whole.
Some kind of array would work but the structure of it is stumping me.
How can I get this to work? PHP solutions would be idea but theoretical will help too.
See if something like this works for you.
// execute query: Select description, amount, id from table
$results = array();
while ($row = $query_result->fetch_array()) {
if (!isset($results[$row['id']])) $results[$row['id']] = array();
$results[$row['id']][] = $row; // push $row to results for this id
}
// later on
foreach($results as $id => $data) {
// output div based on $id
foreach($data as $datum) {
// output individual data item that belongs to $id
}
}
A simple serial solution might look something like this:
$curId = ''; // track working id
$firstDiv = true; // track if inside first div
// open first div
echo '<div>';
// foreach $row
{
// when id changes, transition to new div, except when in first div
if ($row->$id != $curId) {
if ($firstDiv) {
$firstDiv = false;
} else {
// start new div
echo '</div>';
echo '<div>';
}
$curId = $row->$id; // track new current id
}
// display contents of current row
}
// close last div
echo '</div>';
Just store the id in temp variable, if the next one is different close the div and open new div
Assuming associative arrays for the db results:
$final = array();
foreach($results as $result)
{
$final[$result['id']][] = $result;
}
This leaves you with an associative array $final that groups the entries by ID
Below is my code to add the two different query results into one. This is working fine when both the queries have same no.of rows.
eg:
row1 = 1 2 3 (Query1)
row2 = 3 5 5 (Query2)
o/p: 4 7 8
Let's say, I have few rows which are not exactly matched with first query.
eg:
row1 = 1 2 3 2 (Query1)
row2 = 3 empty empty 5 (Query2)
o/p : 4 2 3 7 (I want the o/p to be like this)
empty means there is no data from the second query.
In my while, && working fine when the 2 queries have same no.of rows.
while (($row1 = mysql_fetch_assoc($rs1)) && ($row2 = mysql_fetch_assoc($rs2)))
{
$strHtml .= "<tr>";
$strHtml .= "<td align=center colspan=3>".($row1['Calls']+$row2['Calls'])."</td>";
$strHtml .= "<td align=center colspan=3>".($row1['actual_duration(min)A']+$row2['actual_duration(min)A'])."</td>";
$strHtml .= "<td align=center colspan=3>".($row1['call_usage']+$row2['call_usage'])."</td>";
$strHtml .= "<td align=center colspan=3>".($row1['disconnection_charge']+$row2['disconnection_charge'])."</td>";
$strHtml .= "<td align=center colspan=3>".($row1['total_revenue']+$row2['total_revenue'])."</td>";
$strHtml .= "</tr>";
}
Is the while loop i am using correct or there is any other better solution for this?
please help me, Thanks in advance.
If you don't want to do it all in the SQL query using an OUTER JOIN as #paulsm4 suggests, you might try changing your while to an ||. Then check $row1 and $row2 inside the loop to see if they are empty and calculate your sums accordingly. Is that sufficient? I can put together code if you like...
You could compute all db-side and render a simpler result:
select ifnull(a,0)+ifnull(c,0), ifnull(b,0)+ifnull(d,0) from (select a, b from table1) as x, (select c, d from table2) as y
I can think of a few different ways you can solve this, some in mysql and some in php. I don't know which one you prefer, so I'll list a couple.
mysql solution #1:
Set the default value of your columns to 0, so you will never get empty results. (You'll get 0 instead, and then the addition will work fine)
mysql solution #2:
You can use IFNULL as #Josh suggested, or COALESCE will also work.
php solution #1:
loop through your data, and assign empty values to 0.
foreach($row1 as &$value) {
if(empty($value)) { $value = 0; }
}
unset($value);
foreach($row2 as &$value) {
if(empty($value)) { $value = 0; }
}
unset($value);