473,385 Members | 1,814 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,385 software developers and data experts.

Grouping results by multiple variables

Hello, I'm new here, but am really impressed with the positive attitude! I was wondering if someone could give me some help or point me in the right direction. I have a query that returns the following fields:

city
state
name
serial
category

using this code
[PHP]

$p = '';
$result = mysql_query("SELECT city, state, title, serial, category FROM serials ORDER BY serial, category");

while($row = mysql_fetch_assoc($result))
{
if($row['serial'] == $p)
{
echo "<br />";
$p = $row['serial'];

}else{

echo "<br />";
echo "<br />";
$p = $row['serial'];
}
echo $row["city"];
echo $row["state"];
echo $row["title"];
echo $row["serial"];
echo $row["category"];

}

?>
[/PHP]

This generates the following:
Expand|Select|Wrap|Line Numbers
  1. Toronto     Ontario     Chef     12345     ABC
  2. Detroit     Michigan     Cook      12345  DBF
  3.  
  4. Toronto     Ontario     Cook     12353     ABC
  5.  
  6. Los Angeles California     Waiter  12355  DGG
  7.  
  8. NYC         New York     Janitor 12382  DGG
  9.  
  10. Miami           Florida     Cook     12777     FGH
  11. Fort Worth     Texas         Usher      12777  QWE
  12.  
  13. Dallas            Texas       Cook       22222  FGH
  14.  
  15. NYC         New York     Chef      33333  JKL
  16. Detroit     Michigan     Janitor 33333     DBF
  17.  
I'm not too concerned about the formatting of the results right now.

What I would like to do is to group like results together. Naturally the <serialnum> values are grouped together and broken up by the double line break. What I would like to also group like 'categories' together with the <serialnum> groupings.

Ideally the data above would be represented like this:
Expand|Select|Wrap|Line Numbers
  1. Toronto     Ontario     Chef     12345     ABC
  2. Detroit     Michigan     Cook      12345  DBF
  3. Toronto     Ontario     Cook     12353     ABC
  4. Detroit     Michigan     Janitor 33333     DBF
  5. NYC         New York     Chef      33333  JKL
  6.  
  7. Los Angeles California     Waiter  12355  DGG
  8. NYC         New York     Janitor 12382     DGG
  9.  
  10. Miami           Florida     Cook     12777     FGH
  11. Fort Worth     Texas         Usher      12777  QWE
  12. Dallas            Texas       Cook       22222     FGH
  13.  
So because the <category> field on line 3 matches the <category> field of line 1, it is grouped with the first grouping. Likewise, although the <serial> field of line 4 doesn't match either of lines 1,2,3 the <category> field of line 4 matches that of line 2. Lastly, since the <serial> field of line 5 matches the <serial> field of line 4, it is grouped in the first grouping.

Does this make sense? Sorry, reading it back it doesn't read that well. Let me know if I can make any further clarification.

Most importantly, thanks in advance for any direction that you can provide!

Jake
Aug 15 '07 #1
9 1818
pbmods
5,821 Expert 4TB
Heya, Jake. Welcome to TSDN!

Looking at this part of your code:
Expand|Select|Wrap|Line Numbers
  1. if($row['serial'] == $p)
  2. {
  3.     echo "<br />";        // Note: similar line in else...
  4.     $p = $row['serial'];  // Note: similar line in else...
  5. }
  6. else
  7. {
  8.     echo "<br />";
  9.     echo "<br />";       // Similar line 1
  10.     $p = $row['serial']; // Similar line 2
  11. }
  12.  
Notice that you're really only doing anything if the current value *doesn't* match the previous value. Have a look at this:
Expand|Select|Wrap|Line Numbers
  1. $lastSerial = '';
  2. $lastCat = '';
  3.  
  4. .
  5. .
  6. .
  7.     // Note that we always echo at least one <br />.
  8.     echo '<br />';
  9.  
  10.     // If the current row s/b in a new section, add a <br />.
  11.     if(! (($row['serial'] == $lastSerial) || ($row['category'] == $lastCategory)))
  12.     {
  13.         echo '<br />';
  14.     }
  15.  
  16.     $lastSerial = $row['serial'];
  17.     $lastCat = $row['cat'];
  18.  
Aug 15 '07 #2
Thanks for the warm welcome pbmods!

That definitely cleaned up the code, thank you.

The main thing I'd like it to do is like to put the results into groups based on either variable, <serial> or <category>. So in the first 'text' example above, line 16 should be placed up in the first grouping because the category 'DBF' is already present in the first grouping (line 2).

Hmmm still not too sure I made my question very clear.

Thanks for the quick response, it's great here!

Jake
Aug 15 '07 #3
Hope this is allowed, but I just wanted to bump this and see if anyone had even heard of something like this being capable?

Thanks again!

Jake
Aug 16 '07 #4
jx2
228 100+
well its exist solution for that :-)
but you actuly asked two questions pbmods answer you one of them

the other answer is here

it probably doesnt solve all problems but you get what you want to

look at "GROUP BY WITH ROLLUP"
Aug 17 '07 #5
pbmods
5,821 Expert 4TB
Heya, Jake.

Bumping is allowed on this site. NB as a result, we are extra-hard on double-posting (posting the same problem twice in the same forum).

I'm not sure I understand entirely what you're looking for. If you look at the example you provided:

Expand|Select|Wrap|Line Numbers
  1. Toronto     Ontario     Chef    12345  ABC
  2. Detroit     Michigan    Cook    12345  DBF
  3. Toronto     Ontario     Cook    12353  ABC
  4. Detroit     Michigan    Janitor 33333  DBF
  5. NYC         New York    Chef    33333  JKL
  6.  
  7. Los Angeles California  Waiter  12355  DGG
  8. NYC         New York    Janitor 12382  DGG
  9.  
  10. Miami       Florida     Cook    12777  FGH
  11. Fort Worth  Texas       Usher   12777  QWE
  12. Dallas      Texas       Cook    22222  FGH
  13.  
There's a definite pattern here; between any two rows in the same section, either the serial number is the same, or the category is the same. It seems like (and correct me if I'm wrong) MySQL is returning the results in the proper order, so the logical way to check to see if we need to start a new section would be to compare the current row with the previous one and see if both the serial and the category are different.

Would there be a situation where at least one of the criteria matches, but we should start a new section anyway? And/or are there circumstances where even though neither the serial nor the category matches, but we should still keep the two rows in the same section?
Aug 17 '07 #6
jx2 - Thanks for your reply. As I understand the GROUP BY parameter (including GROUP BY WITH ROLLUP) it will only work if there is an aggregate function in the query. Since I want all lines to be echo'd I don't want to have an aggregate function.

pbmods - Yes and No, but mostly yes. :)

There's a definite pattern here; between any two rows in the same section, either the serial number is the same, or the category is the same.
Yes, thats exactly right. In the following example (as used previously) there are 3 groups, lets call them A, B, C. In group A line 4 doesn't have either the same serial or category as the line directly above it. It does however have the same category as another record from that that group, line 2.

Expand|Select|Wrap|Line Numbers
  1. Toronto     Ontario     Chef    12345  ABC
  2. Detroit     Michigan    Cook    12345  DBF
  3. Toronto     Ontario     Cook    12353  ABC
  4. Detroit     Michigan    Janitor 33333  DBF
  5. NYC         New York    Chef    33333  JKL
  6.  
  7. Los Angeles California  Waiter  12355  DGG
  8. NYC         New York    Janitor 12382  DGG
  9.  
  10. Miami       Florida     Cook    12777  FGH
  11. Fort Worth  Texas       Usher   12777  QWE
  12. Dallas      Texas       Cook    22222  FGH 
Similarly, in Group C, line 12 doesn't have the same serial or category as the line above it, but the category matches that of line 10.

It seems like (and correct me if I'm wrong) MySQL is returning the results in the proper order
Not quite. The results are set to ORDER BY serial, which means that they'll all be grouped together, but the category column is not grouped together.

If I just use the following code as I currently am I could get 5000 results, and while they're sorted by serial, result/line 126 could have the same category as result 3456. Because line 126 has the same category as line 3456 they should be grouped together.

[PHP]
$result = mysql_query("SELECT city, state, title, serial, category FROM serials ORDER BY serial, category");
[/PHP]

Would there be a situation where at least one of the criteria matches, but we should start a new section anyway?
No.

And/or are there circumstances where even though neither the serial nor the category matches, but we should still keep the two rows in the same section?
No.

I just can't seem to wrap my head around how you'd group results based on either of two variables.

Thanks soooo much for your help so far!
Aug 17 '07 #7
pbmods
5,821 Expert 4TB
Heya Jake.

Ok. I see what you're getting at now; I was mistaking the name column for the category column.

Possibly part of the misunderstanding is that in MySQL, the phrase 'GROUP BY' has a slightly different meaning.

I think in your case, you'll need to manually parse your results and organize them that way:
Expand|Select|Wrap|Line Numbers
  1. $_groups = array();
  2. $_idx = array();
  3. while($_row = mysql_fetch_assoc($_res))
  4. {
  5.     if(isset($_idx['serial'][$_row['serial']]))
  6.     {
  7.         $_groups[$_idx['serial'][$_row['serial']]][] = $_row;
  8.         $_idx['category'][$_row['category']] = $_idx['serial'][$_row['serial']];
  9.     }
  10.     elseif(isset($_idx['category'][$_row['category']]))
  11.     {
  12.         $_groups[$_idx['category'][$_row['category']]][] = $_row;
  13.         $_idx['serial'][$_row['serial']] = $_idx['category'][$_row['category']];
  14.     }
  15.     else
  16.     {
  17.         $_groups[][] = $_row;
  18.         end($_groups);
  19.         $_idx['serial'][$_row['serial']] = key($_groups);
  20.         $_idx['category'][$_row['category']] = key($_groups);
  21.     }
  22. }
  23.  
  24. foreach($_groups as $_entries)
  25. {
  26.     foreach($_entries as $entry)
  27.     {
  28.         foreach($entry as $val)
  29.         {
  30.             echo "$val\t";
  31.         }
  32.         echo '<br />';
  33.     }
  34.     echo '<br />';
  35. }
  36.  
Phew! Ok, so what's going on here?

What we're doing is creating a big multi-dimensional array. As we go through, we check to see if we've already processed an entry with the same serial or category. If we have, we assign it to the same group as the last one. Otherwise, we create a new group and update our index.

Going back to everybody's favorite example:
Expand|Select|Wrap|Line Numbers
  1. Toronto* * *Ontario* * *Chef* * 12345* ABC
  2. Detroit* * *Michigan* * Cook* * 12345* DBF
  3. Toronto* * *Ontario* * *Cook* * 12353* ABC
  4. Detroit* * *Michigan* * Janitor 33333* DBF
  5. NYC* * * * *New York* * Chef* * 33333* JKL
  6. *
  7. Los Angeles California* Waiter* 12355* DGG
  8. NYC* * * * *New York* * Janitor 12382* DGG
  9. *
  10. Miami* * * *Florida* * *Cook* * 12777* FGH
  11. Fort Worth* Texas* * * *Usher* *12777* QWE
  12. Dallas* * * Texas* * * *Cook* * 22222* FGH
  13.  
We end up with a $_groups that looks something like this (abbreviated for space):
Expand|Select|Wrap|Line Numbers
  1. Array
  2. (
  3.     [0] => Array
  4.         (
  5.             [0] => Array
  6.                 (
  7.                     [City] => Toronto
  8.                     ...
  9.                     [Serial] => 12345
  10.                     [Cat] => ABC
  11.                 )
  12.             [1] => Array
  13.                 (
  14.                     [City] => Detroit
  15.                     ...
  16.                     [Serial] => 12345
  17.                     [Cat] => DBF
  18.                 )
  19.             .
  20.             .
  21.             .
  22.         )
  23.     [1] => Array
  24.         (
  25.             [0] => Array
  26.                 (
  27.                     [City] => Los Angeles
  28.                     ...
  29.                     [Serial] => 12355
  30.                     [Cat] => DGG
  31.                 )
  32.             [1] => Array
  33.                 (
  34.                     [City] => NYC
  35.                     ...
  36.                     [Serial] => 12382
  37.                     [Cat] => DGG
  38.                 )
  39.         )
  40.     .
  41.     .
  42.     .
  43. )
  44.  
Once we've done all that hard work, the output part is rather trivial....
Aug 17 '07 #8
Yes Yes Yes!

Thank you sooo much pbmods! I've tested this code on a big db and it worked flawlessly. I'm going to spend some time and make sure I understand exactly whats going on.

Thanks so much for all your help, not only in this thread, but also in everyones threads!

Jake
Aug 17 '07 #9
pbmods
5,821 Expert 4TB
Heya, Jake.

Glad to hear you got it working! Good luck with your project, and if you ever need anything, post back anytime :)
Aug 17 '07 #10

Sign in to post your reply or Sign up for a free account.

Similar topics

2
by: Debbie Davis | last post by:
Hi there, SQL 2000 I have the following query: SELECT sponsor, COUNT(sponsor) * 2 AS total FROM Referrals GROUP BY sponsor Works great, returns the sponsor and the total * 2 of their...
4
by: kristofera | last post by:
I am trying to do a distinct grouping of some nodes sorted by a numeric value but for some reason the distinct (preceding-sibling filter) is applied to the result as if not sorted. If I don't use...
2
by: Andreas Håkansson | last post by:
Seeing how my previous post seem to have fallen between the cracks, I thought I would have a second, more direct, go at it. So my question is "Is it possible to group (Muenchian method) over...
3
by: ahaque38 | last post by:
Hello. Using A2K SP3, I am having the following problem with a report using "Sorting and Grouping". I have recently added a grouping in the reports for "Category2<>'CONTRACTS'". I have...
8
by: Mike MacSween | last post by:
tblCourses one to many to tblEvents. A course may have an intro workshop (a type of event), a mid course workshop, a final exam. Or any combination. Or something different in the future. At...
3
by: Gargamil | last post by:
I've written a function to calculate a seriies of parameters based upon some variables. I'd like to be able to return all the parameters to a query. Now all the parameters are interrelated and...
6
by: craig.buchinski | last post by:
Ok, i have a Access Database (which is used with my ESRI Arcmap) and i have written a query for a report to pull out our streetlights and group them by billing wattage. The problem is that it is...
3
by: Shiriah | last post by:
I feel that this is a rather trivial concept that I cannot quite wrap my head around to make work in PHP. I consider myself an intermediate user in SQL (both MSSQL and MySQL) and somewhat novice in...
3
by: kevenj | last post by:
Hello, I'm a bit of a newcomer to PHP and am having an issue I can't overcome. I've read some great posts on the issue of grouping results on this forum 1 and can happily display results under...
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome former...
0
by: ryjfgjl | last post by:
In our work, we often need to import Excel data into databases (such as MySQL, SQL Server, Oracle) for data analysis and processing. Usually, we use database tools like Navicat or the Excel import...
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.