I have a while loop that I use to echo multiple mysql results that translate into offline users. To make things more organized, I wanted to perform the query, store the results in a variable and then echo it at the bottom of the page. I need to echo both online and offline users within a certain parent div, so it seems cluttered to me to echo the first div tag and then perform both queries and echo the results, then echo the closing tag. Currently, if I try to echo the result from outside the while loop, I only get 1 result. If anyone has any ideas, I would appreciate it.
$sql = 'SELECT * FROM users
LEFT JOIN friendships
ON friendships.friend_id = users.id
WHERE friendships.user_id = ?
AND users.id NOT IN (
SELECT active_users.id FROM active_users)';
$stmt5 = $conn->prepare($sql);
$result=$stmt5->execute(array($userid));
while ($row = $stmt5->fetch(PDO::FETCH_ASSOC)) {
$online=htmlspecialchars( $row['username'], ENT_NOQUOTES, 'UTF-8' );
$online = "<div class='user-online'>
<a data-name=\"$to\">$to</a>
</div>";
$online.=etc...plus do other processes
}
<div id=\"online\">
".$online."
</div>
You need to store your SQL results in an array
$sql = 'SELECT * FROM users
LEFT JOIN friendships
ON friendships.friend_id = users.id
WHERE friendships.user_id = ?
AND users.id NOT IN (
SELECT active_users.id FROM active_users)';
$stmt5 = $conn->prepare($sql);
$result=$stmt5->execute(array($userid));
while ($row = $stmt5->fetch(PDO::FETCH_ASSOC)) {
$online[]=htmlspecialchars( $row['username'], ENT_NOQUOTES, 'UTF-8' );
}
<div id=\"online\">
<?php foreach ($online as $aline) {
echo $aline;
} ?>
</div>
I've trimmed some code for clarity but hopefully it helps
Each iteration of the while loop is redefining the $online variable (overwriting it's previous value). You may either define one variable outside of the loop, and append to it in the loop, or store the results in an array, and loop through it to generate the output.
You don't need the while loop. Provided you have enough memory:
$rows = $stmt5->fetchAll(PDO::FETCH_ASSOC);
Related
I am trying to fetch last 10 topics from smf database but topics are in two separate tables.
Subject, Post Time and Message ID in smf_messages.
Topic ID and Topic First Message in smf_topics.
I wrote this code to fetch topics but i dont know how to compare these two results.
$result = mysql_query("select subject,id_msg,id_topic from smf_messages");
$result2= mysql_query("select id_first_msg from smf_topics");
if(mysql_num_rows($result)!=0)
{
while($read = mysql_fetch_object($result))
{
if ($read->id_msg==$read->id_topic) {
echo "<a href='../index.php?topic=" . $read->id_topic . "'>".$read->subject."</a><br>";
}
}
You probably want the following query
select subject, id_msg, id_topic, id_first_msg
from smf_messages
left join smf_topics on smf_message.id_msg = smf_topics.id_first_msg
bind the records by joining in sql:
select subject id_msg, id_topic, id_first_msg from smf_messages
join smf_topics on smf_messages.id_msg = smf_topics.id_topic
mysql have many many options, with a small google search you could found about left join.
tuttorial and examples.
Fist thing you have to do is stop using mysql_* and start using mysqli_* or pdo learn about sql injections
Your query should look like this.
select smf_messages.subject,smf_messages.id_msg,smf_messages.id_topic from smf_messages left join smf_topics on smf_topics.id_first_msg=smf_messages.id_msg
If you want to do that without using SQL, this is my solution it's not good but you can have an idea of how it works:
$messages = array();
$topics = array();
while($readmessage = mysql_fetch_object($resultmessage)) {
array_push($messages, $readmessage);
}
while($readtopic = mysql_fetch_object($resulttopic)) {
array_push($topics, $readtopic);
}
foreach ($topics as $topic) {
$result = array_search($topic->id_first_message);
if($result != true){
//HERE $result IS THE INDEX OF FIRST MESSAGE IF IT IS IN THE MESSAGES ARRAY
$messages[$result].id_msg //Access message attributes
}
}
I'm using this to display information from a queried db in Wordpress. It displays the correct information but it loops it too many times. It is set to display from a SELECT query and depending on the last entry to the db seems to be whether or not it prints double or triple each entry.
foreach ($result as $row) {
echo '<h5><i>'.$row->company.'</i> can perform your window installation for <i>$'.$row->cost.'</i><br>';
echo 'This price includes using<i> '.$row->material.'</i> as your material(s)<br>';
echo '<hr></h5>';
}
Does anyone know what could be producing this error?
Thanks
The query powering that script is:
$result = $wpdb->get_results( "SELECT bp.*, b.company
FROM `windows_brands_products` bp
LEFT JOIN `windows_brands` b
ON bp.brand_id = b.id
JOIN Windows_last_submissions ls
JOIN windows_materials wm
JOIN Windows_submissions ws
WHERE ws.username = '$current_user->user_login'
AND bp.width = ROUND(ls.width)
AND bp.height = ROUND(ls.height)
AND bp.material IN (wm.name)
AND bp.type = ls.type
AND IF (ls.minimumbid != '0.00',bp.cost BETWEEN ls.minimumbid AND ls.maximumbid,bp.cost <= ls.maximumbid)
ORDER BY b.company ASC");
I can't seem to see the duplicate but I agree it must be there.
EDIT-- when I replace the WHERE clause to WHERE ws.username = 'password' , it still repeats. It it displaying a result for each time a result has username='password' , and displaying that set twice as well.
I think you want the following, if you're using MySQLi:
while ($row = $result->fetch_object()) {
echo '<h5><i>'.$row->company.'</i> can perform your window installation for <i>$'.$row->cost.'</i><br>';
echo 'This price includes using<i> '.$row->material.'</i> as your material(s)<br>';
echo '<hr></h5>';
}
Redundant JOIN clauses in my query which was pretty much pulling the same results from two tables (one of which was just a VIEW of the other).
I need to return data from 2 separate tables at the same time. The info I need from the 2nd table is determined by what is returned from the first table. Here's what I'm working with..
$query = "SELECT * FROM pending WHERE paymentid = '".$_GET['vnum']."'";
$result = mysql_query($query);
$num = #mysql_num_rows($result);
$linkid = $res['paymentid'];
if ($num==0) {
echo "Hello, ".$_SESSION['Fname']."<br />There was an error, I cannot find this payment in the records.";
} else {
$picquery = mysql_query("SELECT * FROM _uploads_log WHERE linkid = '".$linkid."'");
$numb = #mysql_num_rows($picquery);
if ($numb==0) {
echo "there is no picture"; }
else {
echo "<img src=\"".$res['log_filename']."\" width=\"100\">"; }
I don't understand how to return the results as an array, if $res[] returns the results for the first query, then what returns the results for the second one?
or is there a better way to do this entirely?
Thank you
You need to do a join, but in order to still get results from your first query even if there is no picture (I assume that's why you split it up) you want a left join.
select * from pending left join _uploads_log on pending.paymentID=$_GET['vnum'] and _uploads_log.linkid = pending.paymentID
(note: php markings removed for readability - you'll have to add them back in)
This should (untested since I don't have your tables) return the full row for your vnum variable and also include the picture data if there is one.
I'm building a simple web app at the moment that I'll one day open source. As it stands at the moment, the nav is generated on every page load (which will change to be cached one day) but for the moment, it's being made with the code below. Using PHP 5.2.6 and MySQLi 5.0.7.7, how more efficient can the code below be? I think joins might help, but I'm after advice. Any tips would be greatly appreciated.
<?php
$navQuery = $mysqli->query("SELECT id,slug,name FROM categories WHERE live=1 ORDER BY name ASC") or die(mysqli_error($mysqli));
while($nav = $navQuery->fetch_object()) {
echo '<li>';
echo ''. $nav->name .'';
echo '<ul>';
$subNavQuery = $mysqli->query("SELECT id,name FROM snippets WHERE category='$nav->id' ORDER BY name ASC") or die(mysqli_error($mysqli));
while($subNav = $subNavQuery->fetch_object()) {
echo '<li>';
echo ''. $subNav->name .'';
echo '</li>';
}
echo '</ul>';
echo '</li>';
}
?>
You can run this query:
SELECT c.id AS cid, c.slug AS cslug, c.name AS cname,
s.id AS sid, s.name AS sname
FROM categories AS c
LEFT JOIN snippets AS s ON s.category = c.id
WHERE c.live=1
ORDER BY c.name, s.name
Then iterate thru the results to create the proper heading like:
// last category ID
$lastcid = 0;
while ($r = $navQuery->fetch_object ()) {
if ($r->cid != $lastcid) {
// new category
// let's close the last open category (if any)
if ($lastcid)
printf ('</li></ul>');
// save current category
$lastcid = $r->cid;
// display category
printf ('<li>%s', $r->cslug, $r->cname);
// display first snippet
printf ('<li>%s</li>', $r->cslug, $r->sname, $r->sname);
} else {
// category already processed, just display snippet
// display snippet
printf ('<li>%s</a>', $r->cslug, $r->sname, $r->sname);
}
}
// let's close the last open category (if any)
if ($lastcid)
printf ('</li></ul>');
Note that I used printf but you should use your own function instead which wraps around printf, but runs htmlspecialchars thru the parameters (except the first of course).
Disclaimer: I do not necessarily encourage such use of <ul>s.
This code is just here to show the basic idea of processing hierarchical data got with one query.
First off, you shouldn't query your database in your view. That would be mixing your business logic and your presentation logic. Just assign the query results to a variable in your controller and iterate through it.
As for the query, yup a join can do that in 1 query.
SELECT * -- Make sure you only select the fields you want. Might need to use aliases to avoid conflict
FROM snippets S LEFT JOIN categiries C ON S.category = C.id
WHERE live = 1
ORDER BY S.category, C.name
This will get you an initial result set. But this won't give you the data nicely ordered like you expect. You'll need to use a bit of PHP to group it into some arrays that you can use in your loops.
Something along the lines of
$categories = array();
foreach ($results as $result) {
$snippet = array();
//assign all the snippet related data into this var
if (isset($categories[$result['snippets.category']])) {
$categories[$result['snippets.category']]['snippet'][] = $snippet;
} else {
$category = array();
//assign all the category related data into this var;
$categories[$result['snippets.category']]['snippet'] = array($snippet);
$categories[$result['snippets.category']]['category'] = $category;
}
}
This should give you an array of categories which have all the related snippets in an array. You can simply loop through this array to reproduce your list.
I'd try this one:
SELECT
c.slug,c.name,s.name
FROM
categories c
LEFT JOIN snippets s
ON s.category = c.id
WHERE live=1 ORDER BY c.name, s.name
I didnt test it, though. Also check the indexes using the EXPLAIN statement so MySQL doesnt do a full scan of the table.
With these results, you can loop the results in PHP and check when the category name changes, and build your output as you wish.
Besides a single combined query you can use two separate ones.
You have a basic tree-structure here with branch elements (categories table) and leaf elements (snippets table). The shortcoming of the single-query solution is that you get owner brach-element repeatedly for every single leaf element. This is redundant information and depending on the number of leafs and the amount of information you query from each branch element can produce large amount of additional traffic.
The two-query solution looks like:
$navQuery = $mysqli->query ("SELECT id, slug, name FROM categories WHERE live=1 ORDER BY name")
or die (mysqli_error ($mysqli));
$subNavQuery = $mysqli->query ("SELECT c.id AS cid, s.id, s.name FROM categories AS c LEFT JOIN snippets AS s ON s.category=c.id WHERE c.live=1 ORDER BY c.name, s.name")
or die (mysqli_error ($mysqli));
$sub = $subNavQuery->fetch_object (); // pre-reading one record
while ($nav = $navQuery->fetch_object ()) {
echo '<li>';
echo ''. $nav->name .'';
echo '<ul>';
while ($sub->cid == $nav->id) {
echo '<li>';
echo ''. $sub->name .'';
echo '</li>';
$sub = $subNavQuery->fetch_object ();
}
echo '</ul>';
}
It should print completely the same code as your example
$navQuery = $mysqli->query("SELECT t1.id AS cat_id,t1.slug,t1.name AS cat_name,t2.id,t2.name
FROM categories AS t1
LEFT JOIN snippets AS t2 ON t1.id = t2.category
WHERE t1.live=1
ORDER BY t1.name ASC, t2.name ASC") or die(mysqli_error($mysqli));
$current = false;
while($nav = $navQuery->fetch_object()) {
if ($current != $nav->cat_id) {
if ($current) echo '</ul>';
echo ''. $nav->cat_name .'<ul>';
$current = $nav->cat_id;
}
if ($nav->id) { //check for empty category
echo '<li>'. $nav->name .'</li>';
}
}
//last category
if ($current) echo '</ul>';
I want to create a (fairly big) Wordpress user index with the users categorized alphabetically, like this:
A
Amy
Adam
B
Bernard
Bianca
and so on.
I've created a custom Wordpress query which works fine for this, except for one problem: It also displays "empty" letters, letters where there aren't any users whose name begins with that letter. I'd be glad if you could help me fix this code so that it only displays the letter if there's actually a user with a name of that letter :) I've tried my luck by checking how many results there are for that letter, but somehow that's not working.
(FYI, I use the user photo plugin and only want to show users in the list who have an approved picture, hence the stuff in the SQL query).
<?php
$alphabet = range('A', 'Z');
foreach ($alphabet as $letter) {
$user_count = $wpdb->get_results("SELECT COUNT(*) FROM wp_users WHERE display_name LIKE '".$letter."%' ORDER BY display_name ASC");
if ($user_count > 0) {
$user_row = $wpdb->get_results("SELECT wp_users.user_login, wp_users.display_name
FROM wp_users, wp_usermeta
WHERE wp_users.display_name LIKE '".$letter."%'
AND wp_usermeta.meta_key = 'userphoto_approvalstatus'
AND wp_usermeta.meta_value = '2'
AND wp_usermeta.user_id = wp_users.ID
ORDER BY wp_users.display_name ASC");
echo '<li class="letter">'.$letter.'';
echo '<ul>';
foreach ($user_row as $user) {
echo '<li>'.$user->display_name.'</li>';
}
echo '</ul></li>';
}
}
?>
Thanks in advance!
Update:
I edited the SQL into this, but now I have the problem that it spits out an </ul> before the first li, which screws up the layout, like this:
</ul>
</li>
<li class="letter">
<div class="letter_head">A</div>
<ul>
<li>Abigail</li>
</ul>
</li>
<li class="letter">
<div class="letter_head">B</div>
<ul>
<li>Bernard</li>
<li>Bianca</li>
</li>
</ul>
It's in general pretty wonky about the ul and li nesting. How can I fix it?
<?php
$qry = "SELECT DISTINCT wp_users.user_login, wp_users.display_name,
LEFT(UPPER(wp_users.display_name), 1) AS first_char
FROM wp_users, wp_usermeta
WHERE UPPER(wp_users.display_name) BETWEEN 'A' AND 'Z'
OR wp_users.display_name BETWEEN '0' AND '9'
AND wp_usermeta.meta_key = 'userphoto_approvalstatus'
AND wp_usermeta.meta_value = '2'
AND wp_usermeta.user_id = wp_users.ID
ORDER BY wp_users.display_name ASC";
$result = mysql_query($qry);
$current_char = '';
while ($row = mysql_fetch_assoc($result)) {
if (!isset($current_char)) {
echo '<li class="letter"><div class="letter_head">'.$current_char.'</div>';
echo '<ul>';
} elseif ($row['first_char'] != $current_char) {
echo '</ul>';
$current_char = $row['first_char'];
echo '<li class="letter"><div class="letter_head">'.$current_char.'</div>';
echo '<ul>';
}
echo '<li>'.$row['display_name'].'</li>';
}
?>
A better solution would be to loop through all users in alphabetical order and for every record check if the first letter differs from that of the last record. If different, you echo out the new letter.
You are doing 52 database calls. Is the user table too big to grab all of them in one query? Also, I believe the order by on the count is unnecessary. I do not know if MySQL ignores it or not.
Your problem is get_results returns an single element array every time for the count query. So $user_count > 0 is always returning true. (I don't understand PHP logic most of the time. Is an array greater than zero?). You need to do something like $user_count[0] to get at the actual number.