Parsing one col of multiple rows php - php

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.

Related

PHP while loop to fetch post data from database

I am creating my own blog from scratch with a homepage that loads the latest posts in order of time published. I call the posts using a front controller and store the data on a MySQL database. The website itself is great and the posts all load perfectly with no issue. The issue is getting the homepage to work.
I created a few PHP functions for the homepage. They generally order the posts (database rows) by ID in descending order, since it's an autoincrement field, and call their data. And then to show the latest post as a sort of 'featured post' right at the top, by fetching the data from the very top row in the database, which is the latest post.
And that works fine - when I echo the result it shows the latest post just as I want it.
Below that I want two boxes, side by side, for the two posts before the first one. So I made this function to call them:
function fetch_rest_posts_1($conn) {
$stuff = $conn->query("SELECT * FROM table WHERE is_post = 1 ORDER BY id DESC LIMIT 1,2");
while ($row = $stuff->fetch_array()) {
$i=1;
return '<div id="post_'.$i.'" style="width:308px;height:215px;padding:5px">
<h2>'.$row['title'].'</h2>
<p>'.date('d/m/Y',strtotime($row['published_date'])).' by '.$row['author'].' | </p>
<p>'.$row['meta_description'].'</p>
</div>';
$i++;
} // style="white-space:nowrap;width:100%;overflow:hidden;text-overflow:ellipsis"
}
And it actually does work great when I echo the result, shows everything I want, but it only shows one div, not two. When I take the SQL query and directly enter it into phpMyAdmin, it gives me two rows. Have I done something wrong?
(I put the auto-increasing $i in there so that I could isolate each box and alter the style later.)
Your problem is caused by the return statement in the loop. You should add $return = '' at the top of your function, replace return by $result .=, and return $result at the end of your function.
In addition, the loop counter $i is reset in every iteration. Move the initial assignment out of the loop.
EDIT: The .= is intentional to append to $result instead of replacing it with another value constructed from the next dataset.
initiate $i outside the loop and use echo() instead of return()
return() breaks the loop
or use
$result .= '<div id="post_'.$i.'" style="width:308px;height:215px;padding:5px">
<h2>'.$row['title'].'</h2>
<p>'.date('d/m/Y',strtotime($row['published_date'])).' by '.$row['author'].' | </p>
<p>'.$row['meta_description'].'</p>
</div>';
and return $result; after the loop
That's because return will stop execution of the function try this approach:
function fetch_rest_posts_1($conn) {
$stuff = $conn->query("SELECT * FROM table WHERE is_post = 1 ORDER BY id DESC LIMIT 1,2");
$post = array();
while ($row = $stuff->fetch_array()) {
$post[] = $row;
}
return $post;
}
So the function purpose is to just get the data, so you can later print it:
$row = fetch_rest_posts_1($conn);
for($i = 0; count(row); $i++){
echo '<div id="post_'.$i.'" style="width:308px;height:215px;padding:5px">
<h2>'.$row[$i]['title'].'</h2>
<p>'.date('d/m/Y',strtotime($row['published_date'])).' by '.$row[$i]['author'].' | </p>
<p>'.$row[$i]['meta_description'].'</p>
</div>';
}

What is my last row_number in mysql query?

I have a query like this:
$sql = "SELECT * FROM doctors WHERE city ='$city' LIMIT 10 ";
$result = $db->query($sql);
And I show the result like this :
while($row = $result->fetch_object()){
echo $row->city;
}
The Problem :
Mysql , will search through my database to find 10 rows which their city field is similar to $city.
so far it is OK;
But I want to know what is the exact row_number of the last result , which mysql selected and I echoed it ?
( I mean , consider with that query , Mysql selected 10 rows in my database
where row number are:
FIRST = 1
Second = 5
Third = 6
Forth = 7
Fifth = 40
Sixth = 41
Seventh = 42
Eitghth = 100
Ninth = 110
AND **last one = 111**
OK?
I want to know where is place of this "last one"????
)
MySQL databases do not have "row numbers". Rows in the database do not have an inherent order and thereby no "row number". If you select 10 rows from the database, then the last row's "number" is 10. If each row has a field with a primary id, then use that field as its "absolute row number".
You could let the loop run and track values. When the loop ends, you will have the last value. Like so:
while($row = $result->fetch_object()){
echo $row->city;
$last_city = $row->city;
}
/* use $last_city; */
To get the row number in the Original Table of the last resultant (here, tenth) row, you could save the data from the tenth row and then, do the following:
1. Read whole table
2. Loop through the records, checking them against the saved data
3. Break loop as soon as data found.
Like So:
while($row = $result->fetch_object()){
echo $row->city;
$last_row = $row;
}
Now, rerun the query without filters:
$sql = "SELECT * FROM doctors";
$result = $db->query($sql);
$rowNumber = 0;
while($row = $result->fetch_object()) {
if($row == $last_row) break;
$rowNumber++;
}
/* use $rowNumber */
Hope this helps.
What you can do is $last = $row->id; (or whatever field you want) inside your while loop - it will keep getting reassigned with the end result being that it contains the value of the last row.
You could do something like this:
$rowIndex = 0;
$rowCount = mysqli_num_rows($result);
You'd be starting a counter at zero and detecting the total number of records retrieved.
Then, as you step through the records, you could increment your counter.
while ( $row = $result->fetch_object() ) {
$rowIndex++;
[other code]
}
Inside the While Loop, you could check to see whether the rowIndex is equal to the rowCount, as in...
if ($rowIndex == $rowCount) {
[your code]
}
I know this is a year+ late, but I completely why Andy was asking his question. I frequently need to know this information. For instance, let's say you're using PHP to echo results in a nice HTML format. Obviously, you wouldn't need to know the record result index in the case of simply starting and ending a div, because you could start the div before the loop, and close it at the end. However, knowing where you are in the result set might affect some styling decisions (e.g., adding particular classes to the first and/or last rows).
I had one case in which I used a GROUP BY query and inserted each set of records into its own tabbed card. A user could click the tabs to display each set. I wanted to know when I was building the last tab, so that I could designate it as being selected (i.e., the one with the focus). The tab was already built by the time the loop ended, so I needed to know while inside of the loop (which was more efficient than using JavaScript to change the tab's properties after the fact).

Grouping a SQL result set in PHP

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

Database data in PHP array

I have a table in phpmyadmin that stores an 'id' (auto inc), 'title' and a 'date'.
I have a webpage where I display the 10 latest items (I simply order by ID).
On that page I print the title and the date. My wish is to also display the number of the posted item, so the first posted item is 1, the second is 2, etc. I cannot simply print the ID from the database because if I delete a row, the numbers aren't straight anymore.
My idea was to put all the data in an array but I have no clue what the best way to do this is and how I could print that item number. So for example when I want to display the 54th item I can easily print $items[54][id] or something and it will show me the number 54 and to display the title I print $items[54][title].
I don't know if there are simpler methods, plus arrays always start at 0, but my items must start at 1.
Besides this page that shows the 10 latest items, there is another page where it gets the title of the item out of the URL. How will I be able to search the title in the array and display the data the same way but only for that requested title?
Thanks in advance!
"SELECT COUNT(id) as cnt FROM mytable";
you can select the count of all database entries.
and then assign it to your iterator
$i = $row['cnt']; // this will hold the ammount of records e.g. 21
// other query
while($row = mysql_fetch_assoc($result)) {
echo $i;
$i--; // this will decrement on every iteration 21, 20 , 19, and so on.
}
First off. I would add a timestamp field to the database and order by that instead as it feels overall more reliable and gives you additional details which may prove handy later.
To create the multidimensional array I would do something like:
$result = mysql_query(...);
$items = array();
while($item = mysql_fetch_assoc($result)) {
$items[] = $item;
}
Now $items[12] for example would give you item number 13 (since it's 0-indexed).
Lastly, to select only the item with a specific title I would use a query which included a WHERE clause, like
"SELECT ... FROM ... WHERE title = '".$title."'"
It's very important to sanitize this variable before using it in the query though.
You can read more about MySQL on a lot of places. A quick googling gave me this: http://www.tutorialspoint.com/mysql/index.htm
You should learn PHP before starting to program in PHP ;) Read and work through the PHP manual and some tutorials!
As to your question it is a simple loop you want to do. One way of doing it as an example.
Fetch the 10 last items from the database in any way you like, following some code, partly pseudo-code.
$markup = '';
for ($i=1; $i<=count($items); $i++)
{
$markup .= 'Item ' . $i . ': ' . $items['date'] . ' - ' . $items['title'];
$markup .= 'read more';
$markup .= PHP_EOL;
}
echo $markup;
I don't know how you print out your data exactly, but I assume there is a loop in there. Simply set a counter that increments by one at every row and print its value.
As for the title search, you'll have to run another query with a WHERE title = '$title' condition, but beware of SQL injection.

Possibly simple PHP/MYSQL issue with retrieving and showing data

I have been racking my brains over this for a while now. Here is the data I have in the SQL data base as an example:
ID | TYPE | DATA
1 | TXT | TEST
2 | PHP | php
3 | JS | JAVASCRIPT
That is just an example, there are multiple listing for TXT, PHP and JS throughout the table. What I want to do is retrive all the data and display it all into separate drop down/select boxes. Meaning, select box one would list all data with type TXT, select box two would list all data with type PHP and select box 3 would list all data with type JS. The only way I have came about doing this is doing individual sql queries for each different type. I know there is a way to do it all in 1 query and then display it the way I want to but I just can't seem to figure out how and I know its going to drive me nuts when someone helps and I see just how they did it.
The only way that I know of to get all of the data in one query is just to do a generic SELECT * FROM tbl, and then you can group them in the code:
$res = mysqli_query('SELECT * FROM tbl');
$data = array();
while($row = mysql_fetch_assoc($res)) {
$type = $row['type'];
$data[$type][] = $row;
}
// $data contains all of the record, grouped by the TYPE column
foreach($data as $type => $records) {
echo "records for $type: <select>";
foreach($records as $record) {
echo "<option value='$id'>$id</option>";
}
echo "</select>";
}
Just retrieve all records and loop through them using PHP. Use an iterator if the recordset is going to be huge to prevent using too much memory.
$lists = array();
foreach($recordset as $record) {
$lists[$record['type']][$record['id']] = $record['data'];
}
Know you have an array containing all data.
Just order it by Type and make a loop using "foreach" into the results, changing of select box when the type is different than the preivous.
In this way you only loop once over the array.
You can do kind of grouping with "ORDER BY TYPE":
SELECT id, data
FROM table
ORDER BY type;
Then, in data output loop you can track current type, and build another select box once type changed:
$currentType = "no type";
while($row = mysql_fetch_assoc($res)) {
if ($currentType != $row['type']) {
$currentType = $row['type'];
// start new select box here
}
// do some other work here
}
BTW, such approach looks like kind of hack :)

Categories