PHP while loop find last row - php

$sql = mysql_query("SELECT * FROM comments WHERE user = 1");
$i = 1;
while ($row = mysql_fetch_assoc($sql)) {
<p>$i. <?php echo $row['comment'] ?></p>
<div class="border"></div>
$i++;
}
How could I do to not output <div class="border"></div> under the last comment?

$sql = mysql_query("SELECT * FROM comments WHERE user = 1");
$number = mysql_num_rows($sql);
$i = 1;
while ($row = mysql_fetch_assoc($sql)) {
echo '<p>' . $i . $row['comment'] . '</p>';
if ($i < $number)
{
echo '<div class="border"></div>';
}
$i ++;
}
Using WebDevHobo's suggestion.

$sql = mysql_query("SELECT * FROM comments WHERE user = 1");
$output = array ();
while ($row = mysql_fetch_assoc($sql)) {
$output[] = $row['comment'];
}
echo join('<div class="border"></div>', $output);

$number = mysql_num_rows($sql);
This will tell you how many rows will be returned. Based on that, you can make sure that the last on does not have the DIV.

$sql = mysql_query("SELECT * FROM comments WHERE user = 1");
$i = 1;
while ($row = mysql_fetch_assoc($sql)) {
$out_data[] = "<p>$i {$row['comment']} </p>";
$i++;
}
$divider = '<div class="border"></div>';
$output = implode ($divider, $out_data);
echo $output;

$rslt = mysql_query("SELECT * FROM comments WHERE user = 1");
$i = 1;
if ($row = mysql_fetch_assoc($rslt)) {
echo '<p>'. $i . ' '. $row['comment'] . '</p>';
$i++;
while ($row = mysql_fetch_assoc($rslt)){
echo '<div class="border"></div>';
echo '<p>'. $i . ' ' . $row['comment'] . '</p>';
$i++;
} // end while
} // end if
Avoids needing to know the number of rows.
Executes the if statement only once instead of each loop.
The HTML and php were kind of messy and inconsistent, so I just assumed the whole block was within php tags. Obviously, open and close the php tag as you see fit.
This is largely a style issue, but I decided that the variable name $sql was a bit misleading, as it is often and commonly used to hold the string of the sql statement to be executed, I therefore changed the variable name to $rslt.

A general answer to this type of problem, and using Javascript because it's easy to throw in a console and play with:
var count = 0;
var foo = 3;
while( count < 3 ) {
console.log("Header - " + count);
console.log("Body - "+ count);
console.log("Footer - " + count);
count++;
}
This will print:
Header - 0
Body - 0
Footer - 0
Header - 1
Body - 1
Footer - 1
Header - 2
Body - 2
Footer - 2
The case being requested is basically saying "Print a footer on all but the last element."
If you consider the second loop iteration as simply a continuation of the first you can see how to do this without needing to find the total number of records - e.g. no need to do a second query for count. More succinctly: when you're stuck trying to figure out how to do something using a loop (or recursion) you should try actually writing out what your loop does, but without actually looping - e.g. copy and paste the loop block at least three times.
Rather than do that here, I'm just going to finish with the answer, and leave the derivation to the reader :~)
var count = 0;
var foo = 3;
while( count < 3 ) {
if( count > 0 ) {
console.log("Footer - " + (count - 1));
}
console.log("Header - " + count);
console.log("Body - "+ count);
count++;
}

Related

PHP Loop - dealing with non-sequential iterations

I have the following code - it produces a series of queries that are sent to a database:
$a = 'q';
$aa = 1;
$r = "$a$aa";
$q = 54;
while($aa <= $q){
$query .= "SELECT COUNT(". $r .") as Responses FROM tresults;";
$aa = $aa + 1;
$r = "$a$aa";
}
The issue I have is simple, within the database, the number is not sequential.
I have fields that go from q1 to q13 but then goes q14a, q14b, q14c, q14d and q14e and then from q15 to q54.
I've looked at continue but that's more for skipping iterations and hasn't helped me.
I'm struggling to adapt the above code to handle this non-sequential situation. Any ideas and suggestions welcomed.
I have fields that go from q1 to q13 but then goes q14a, q14b, q14c, q14d and q14e and then from q15 to q54.
for($i=1; $i<=54; ++$i) {
if($i != 14) {
echo 'q' . $i . "<br>";
}
else {
for($j='a'; $j<='e'; ++$j) {
echo 'q14' . $j . "<br>";
}
}
}
If you don’t need to execute the statements in order of numbering, then you could also just skip one in the first loop if the counter is 14, and then have a second loop (not nested into the first one), that does the q14s afterwards.
You could get the columns from the table and test to see if they start with q (or use a preg_match):
$result = query("DESCRIBE tresults");
while($row = fetch($result)) {
if(strpos($row['Field'], 'q') === 0) {
$query .= "SELECT COUNT(". $r .") as Responses FROM tresults;";
}
}
Or build the columns array and use it:
$columns = array('q1', 'q2', 'q54'); //etc...
foreach($columns as $r) {
$query .= "SELECT COUNT(". $r .") as Responses FROM tresults;";
}

Display in table format from mysql

I have table with product_category and its has more than 20 categories and I want to display them in table format like below image
I like to place categories in 5 td then how I can be fixed towards tr in a table
Below is code I have tried, but its not giving the desired output
And below is the image that might be solution I needed
Below code
<table>
<?php
$fquery5 = mysql_query("select Cat_ID, Cat_Name from product_category where Active_Flag=1");
$count1 = mysql_num_rows($fquery5);
$hor_length = 5;
$ver_length = $count1 / $hor_length;
$data1 = mysql_fetch_row($fquery5);
for ($i = 0; $i <= $ver_length; $i++) {
echo "<tr>";
for ($j = $i + $hor_length; $j <= $count1; $j++) {
echo "<td>";
echo "Id : " . $data1[0] . " = " . $data1[1];
echo "</td>";
}
echo "</tr>";
}
?>
</table>
Added resultant output image answered by #DaveRandom
Try this (FIXED):
<?php
// Number of columns
$hor_length = 5;
// Do the query, get the number of rows in the result
$fquery5 = mysql_query("
SELECT Cat_ID, Cat_Name
FROM product_category
WHERE Active_Flag = 1
");
$numrows = mysql_num_rows($fquery5);
// Start of table
echo "<table>\n<tr>\n";
// Loop the results with a counter
for ($i = 1; $row = mysql_fetch_row($fquery5); $i++) {
// Every iteration echos a cell
echo "<td>Id : " . $row[0] . " = " . $row[1] . "</td>\n";
// If we're at the end of a row, echo a row break, unless it is the last result
if (!($i % $hor_length) && $i < $numrows) {
echo "</tr>\n<tr>\n";
}
}
// Right-pad the end row with empty cells
for ($i--; $i % $hor_length; $i++) {
echo "<td></td>\n";
}
// Echo the end of the table
echo "</tr>\n</table>";
See a working example (manually created the data array since I can't query a DB from codepad)

PHP loop to sort table

I'm querying a database for names that are numbered 1-26 alphabetically. I have the following code, but since HTML is structured tr then td, the table appears alphabetically by row as opposed to by column. How can I make it appear in order by column?
$query = mysql_query("SELECT name FROM people WHERE main=1 ORDER BY id");
$i = 0;
while($result = mysql_fetch_array($query)) {
$name = $result['name'];
if ($i % 5 == 0) echo "<tr>\n";
echo "<td width=\"150\">";
echo "".$name."<br />";
echo "</td>\n";
$i++;
if ($i % 5 == 0) echo "</tr>\n";
};
alpha beta charlie
delta echo foxtrot
vs.
alpha charlie echo
beta delta foxtrot
Also, I'm open to reworking the code if there's a more efficient way.
You could just access the output array in strides. Compute how many rows you need as the number of results divided by 5, and use the row count as the stride.
$ncols = 5;
$nrows = $nresults / $ncols + ($nresults % $ncols == 0 ? 0 : 1);
for ($i = 0; $i < $nrows; $i++)
{
// start row
for ($j = 0; $k < $ncols; $j++)
{
// print $results[$nrows * $j + $i]
}
// end row
}
You'll have to transfer your query results into an array $results first. Since you'll have to know the total number of results, this is sort of mandatory, though I'd be curious if anyone has a solution that can work while fetching the results.
Update: See Justin's answer for a cool solution that grows the output while fetching the query results line by line. Since it's currently being worked on, here's a summary (credits to Justin):
$nresults = mysql_num_rows($query);
$ncols = 5;
$nrows = (int) ceil($nresults / $ncols);
$i = 0; $cols = array_fill(0, $nrows, "");
while ($result = mysql_fetch_array($query))
$cols[$i++ % $nrows] .= "<td>$result['name']</td>";
echo "<tr>" . implode("</tr><tr>", $cols) . "</tr>";
Edit:
After the discussion in the comments between myself, Kerrek SB and the OP bswinnerton, the following code seems to be the most effective:
$columns = 3;
$rowcount = mysql_num_rows($query);
$rows = ceil($rowcount / $columns);
$rowdata = array_fill(0, $rows, "");
$ctr = 0;
while ($result = mysql_fetch_array($query))
$rowdata[$ctr++ % $rows] .= '<td>'.$result['name'].'</td>';
echo '<tr>'.implode('</tr><tr>',$rowdata).'</tr>';
This will create three columns, filled vertically (my original answer would create three rows). It also properly initializes the array (preventing PHP warnings), yields a correct row count for result counts that aren't divisible by the column count, and incorporates Kerrek's clever "calc-row-in-the-subscript" trick.
Original Post:
You could use arrays and implode() This way, you only have to make one pass through your results:
$row = 0;
$rows = 3;
$rowdata = array();
while($result = mysql_fetch_array($query))
{
if ($row >= $rows) $row = 0;
$rowdata[$row++] .= '<td>'.$result['name'].'</td>';
}
echo '<tr>'.implode('</tr><tr>',$rowdata).'</tr>';

How to add a seperator between menu items in PHP but not on the end

I'm trying to put an image as a separator between menu items but not on the outside and I'm not sure how to do this.. So it would end up being something like this:
HOME | ABOUT | CONTACT
unfortunately my code puts one after every entry including the last one.
mysql_select_db($database_db_connection, $db_connection);
$query_rsMenu = "SELECT * FROM menu WHERE online = 1 ORDER BY position ASC";
$rsMenu = mysql_query($query_rsMenu, $db_connection) or die(mysql_error());
echo "<ul class='MenuBarVertical'>\n";
while($row_rsMenu = mysql_fetch_assoc($rsMenu)) {
echo (" <li>" . $row_rsMenu['menuName'] . " <img src='SiteFiles/Site/separator.jpg' /> </li>\n");
}
echo "</ul>\n";
mysql_free_result($rsMenu);
Thanks
You could also build an array and use implode when you print it out. This also separates the database model from the view a little better.
mysql_select_db($database_db_connection, $db_connection);
$query_rsMenu = "SELECT * FROM menu WHERE online = 1 ORDER BY position ASC";
$rsMenu = mysql_query($query_rsMenu, $db_connection) or die(mysql_error());
$array = array();
while($row_rsMenu = mysql_fetch_assoc($rsMenu)) {
$array[] = "<li>" . $row_rsMenu['menuName'] . "</li>\n";
}
mysql_free_result($rsMenu);
echo "<ul class='MenuBarVertical'>\n";
echo implode(' <img src="SiteFiles/Site/separator.jpg" /> ', $array);
echo "</ul>\n";
Of course the tags end up between the li instead of inside, but since you are making the li inline I think it will work.
The easy solution is to special case either the last iteration or the first one. The first one is usually easier: set $first = true outside the loop, inside the loop: if (!$first) { print 'separator'; }.
$count = 0;
$dbRows = mysql_num_rows($rsMenu);
while($row_rsMenu = mysql_fetch_assoc($rsMenu)) {
$count++;
echo (" <li><a href=\"../" . $row_rsMenu['menuURL'] . "\">" . $row_rsMenu['menuName'];
if($count < $dbRows)
echo ("</a> <img src='SiteFiles/Site/separator.jpg' /> </li>\n");
}
You could use mysql_num_rows() to get the number of rows from the result set, and build some logic against the result.
Yet another answer :
for ($i = 1; $i <= mysql_num_rows($rsMenu); $i++) {
$row_rsMenu = mysql_fetch_assoc($rsMenu);
// do something;
if ($i == mysql_num_rows($rsMenu) - 1) {
// this is the last element, do something;
}
}

What's the best way to generate a tag cloud from an array using h1 through h6 for sizing?

I have the following arrays:
$artist = array("the roots", "michael jackson", "billy idol", "more", "and more", "and_YET_MORE");
$count = array(5, 3, 9, 1, 1, 3);
I want to generate a tag cloud that will have artists with a higher number in $count enclosed in h6 tags and the lowest enclosed h1 tags.
You will want to add a logarithmic function to it too. (taken from tagadelic, my Drupal module to create tag clouds http://drupal.org/project/tagadelic):
db_query('SELECT COUNT(*) AS count, id, name FROM ... ORDER BY count DESC');
$steps = 6;
$tags = array();
$min = 1e9;
$max = -1e9;
while ($tag = db_fetch_object($result)) {
$tag->number_of_posts = $tag->count; #sets the amount of items a certain tag has attached to it
$tag->count = log($tag->count);
$min = min($min, $tag->count);
$max = max($max, $tag->count);
$tags[$tag->tid] = $tag;
}
// Note: we need to ensure the range is slightly too large to make sure even
// the largest element is rounded down.
$range = max(.01, $max - $min) * 1.0001;
foreach ($tags as $key => $value) {
$tags[$key]->weight = 1 + floor($steps * ($value->count - $min) / $range);
}
Then in your view or template:
foreach ($tags as $tag) {
$output .= "<h$tag->weight>$tag->name</h$tag->weight>"
}
Off the top of my head...
$artist = array("the roots","michael jackson","billy idol","more","and more","and_YET_MORE");
$count = array(5,3,9,1,1,3);
$highest = max($count);
for (int $x = 0; $x < count($artist); $x++)
{
$normalized = $count[$x] / $highest;
$heading = ceil($normalized * 6); // 6 heading types
echo "<h".$heading.">".$artist[$x]."</h".$heading.">";
}
Perhaps this is a little academic and off topic but hX tags are probably not the best choice for a tag cloud for reasons of document structure and all that sort of thing.
Maybe spans or an ol with appropriate class attributes (plus some CSS)?
Have used this snippet for a while, credit is prism-perfect.net. Doesn't use H tags though
<div id="tags">
<div class="title">Popular Searches</div>
<?php
// Snippet taken from [prism-perfect.net]
include "/path/to/public_html/search/settings/database.php";
include "/path/to/public_html/search/settings/conf.php";
$query = "SELECT query AS tag, COUNT(*) AS quantity
FROM sphider_query_log
WHERE results > 0
GROUP BY query
ORDER BY query ASC
LIMIT 10";
$result = mysql_query($query) or die(mysql_error());
while ($row = mysql_fetch_array($result)) {
$tags[$row['tag']] = $row['quantity'];
}
// change these font sizes if you will
$max_size = 30; // max font size in %
$min_size = 11; // min font size in %
// get the largest and smallest array values
$max_qty = max(array_values($tags));
$min_qty = min(array_values($tags));
// find the range of values
$spread = $max_qty - $min_qty;
if (0 == $spread) { // we don't want to divide by zero
$spread = 1;
}
// determine the font-size increment
// this is the increase per tag quantity (times used)
$step = ($max_size - $min_size)/($spread);
// loop through our tag array
foreach ($tags as $key => $value) {
// calculate CSS font-size
// find the $value in excess of $min_qty
// multiply by the font-size increment ($size)
// and add the $min_size set above
$size = $min_size + (($value - $min_qty) * $step);
// uncomment if you want sizes in whole %:
// $size = ceil($size);
// you'll need to put the link destination in place of the /search/search.php...
// (assuming your tag links to some sort of details page)
echo '<a href="/search/search.php?query='.$key.'&search=1" style="font-size: '.$size.'px"';
// perhaps adjust this title attribute for the things that are tagged
echo ' title="'.$value.' things tagged with '.$key.'"';
echo '>'.$key.'</a> ';
// notice the space at the end of the link
}
?>
</div>
#Ryan
That's correct but it actually makes the tags with the least number, larger. This code has been tested:
$artist = array("the roots","michael jackson","billy idol","more","and more","and_YET_MORE");
$count = array(5,3,9,1,1,3);
$highest = max($count);
for ($x = 0; $x < count($artist); $x++) {
$normalized = ($highest - $count[$x]+1) / $highest;
$heading = ceil($normalized * 6); // 6 heading types
echo "<h$heading>{$artist[$x]}</h$heading>";
}
This method is for SQL/PostgreSQL fanatics. It does the entire job in the database, and it prints text with "slugified" link. It uses Doctrine ORM just for the sql call, I'm not using objects.
Suppose we have 10 sizes:
public function getAllForTagCloud($fontSizes = 10)
{
$sql = sprintf("SELECT count(tag) as tagcount,tag,slug,
floor((count(*) * %d )/(select max(t) from
(select count(tag) as t from magazine_tag group by tag) t)::numeric(6,2))
as ranking
from magazine_tag mt group by tag,slug", $fontSizes);
$q = Doctrine_Manager::getInstance()->getCurrentConnection();
return $q->execute($sql);
}
then you print them with some CSS class, from .tagranking10 (the best) to .tagranking1 (the worst):
<?php foreach ($allTags as $tag): ?>
<span class="<?php echo 'tagrank'.$tag['ranking'] ?>">
<?php echo sprintf('<a rel="tag" href="/search/by/tag/%s">%s</a>',
$tag['slug'], $tag['tag']
); ?>
</span>
<?php endforeach; ?>
and this is the CSS:
/* put your size of choice */
.tagrank1{font-size: 0.3em;}
.tagrank2{font-size: 0.4em;}
.tagrank3{font-size: 0.5em;}
/* go on till tagrank10 */
This method displays all tags. If you have a lot of them, you probably don't want your tag cloud to become a tag storm. In that case you would append an HAVING TO clause to your SQL query:
-- minimum tag count is 8 --
HAVING count(tag) > 7
That's all
I know it's a very old post, still I'm posting my view as it may help someone in future.
Here is the tagcloud I used in my website:
http://www.vbausefulcodes.in/
<?php
$input= array("vba","macros","excel","outlook","powerpoint","access","database","interview questions","sendkeys","word","excel projects","visual basic projects","excel vba","macro","excel visual basic","tutorial","programming","learn macros","vba examples");
$rand_tags = array_rand($input, 5);
for ($x = 0; $x <= 4; $x++) {
$size = rand ( 1 , 4 );
echo "<font size='$size'>" . $input[$rand_tags[$x]] . " " . "</font>";
}
echo "<br>";
$rand_tags = array_rand($input, 7);
for ($x = 0; $x <= 6; $x++) {
$size = rand ( 1 , 4 );
echo "<font size='$size'>" . $input[$rand_tags[$x]] . " " . "</font>";
}
echo "<br>";
$rand_tags = array_rand($input, 5);
for ($x = 0; $x <= 4; $x++) {
$size = rand ( 1 , 4 );
echo "<font size='$size'>" . $input[$rand_tags[$x]] . " " . "</font>";
}
?>
As a helper in Rails:
def tag_cloud (strings, counts)
max = counts.max
strings.map { |a| "<span style='font-size:#{((counts[strings.index(a)] * 4.0)/max).ceil}em'>#{a}</span> " }
end
Call this from the view:
<%= tag_cloud($artists, $counts) %>
This outputs <span style='font-size:_em'> elements in an array that will be converted to a string in the view to ultimately render like so:
<span style='font-size:3em'>the roots</span>
<span style='font-size:2em'>michael jackson</span>
<span style='font-size:4em'>billy idol</span>
<span style='font-size:1em'>more</span>
<span style='font-size:1em'>and more</span>
<span style='font-size:2em'>and_YET_MORE</span>
It would be better to have a class attribute and reference the classes in a style sheet as mentioned by Brendan above. Much better than using h1-h6 semantically and there's less style baggage with a <span>.

Categories