How to optimize while loop with SQL query? - php

$id = $user['id']; // the ID of the logged in user, we are retrieving his friends
$friends = $db->query("SELECT * FROM friend_requests WHERE accepted='1' AND (user1='".$id."' OR user2='".$id."') ORDER BY id DESC");
while($friend = $friends->fetch_array()) {
$fr = $db->query("SELECT id,profile_picture,age,full_name,last_active FROM users WHERE (id='".$friend['user1']."' OR id='".$friend['user2']."') AND id != '".$id."'")->fetch_array();
echo $fr['age'];
}
I am basically looping through all my friends, and getting information about each one.
How would I ago about optimizing this, I am aware that that it is inefficient to run this query so many times, considering there are thousands of "friends", but I'm not exactly sure how to go about optimizing it. Any help is appreciated, thanks.

That article in the comments is great. You're definitely going to want to figure out how to write the join yourself. Here's my attempt at writing it for you. While you're rewriting the query, you might want to not * columns from friend_requests (or any at all since you're going to use the join). Any column you pull will have to be loaded into memory so any you can avoid pulling will help out. Especially if you're PHP server and your DB server are not on the same machine (less data over the network).
Anyway, here's my shot in the dark:
$id = $user['id'];
$friends = $db->prepare("
SELECT
freq.*
,users.id AS users_id
,users.profile_picture
,users.age
,users.full_name
,users.last_active
FROM friend_requests freq
INNER JOIN users u ON users.id IN (freq.user1,freq.user2) AND freq.id != u.id
WHERE
freq.accepted='1'
AND ? IN (freq.user1,freq.user2
ORDER BY freq.id DESC");
if($friends) {
$friends->bindParam("s",$id);
if($friends->execute()) {
// get_result() only works if you have the MySQL native driver.
// You'll find out real quick if you don't
$myFriends = $friends->get_result();
while($row = $myFriends->fetch_assoc()) {
echo $row['age'];
}
}
}
else {
printf("SQL Error: %s.<br>\n", $friends->error);
}
// cleanup
$friends->close();
quick reference: get_result()

Related

How can I select all id's from a sql table in descending order and then echo them (in php)?

I have several id's in a table called "leaderboards" that belong to different users. They're named as:"id_user" and they're not in order. What I want to do is printing divs in a leaderbord which should contain some info that I get from those id_user's.
The only problem I have about it is that after a research on stackoverflow and other websites, I still couldn't find how to select those id_user's in descending order AND be able to take one by one to get the info from that user and then continue with the next id_user, and so on.
I don't know how to select the specific row of each id_user in descending order to do the other codes that I already know how to do.
I hope it's not a duplicate of any other previosly asked question on this website (I really did a research and I couldn't find any specific answer to this question, for the sql part and the php part all together).
Thank you so so much beforehand.
An INNER JOIN between your tables will achieve what you intend.
SELECT *
FROM users
JOIN leaderboards WHERE users.id = leaderboards.id_user
ORDER BY users.id DESC
In each returned row, you will get the columns from both your users and leaderboards tables, so loop over the result and echo the information from the user you need.
$query = 'SELECT...';
$res = mysqli_query($query);
while ($row = mysqli_fetch_assoc($res)) {
echo '<div>'.$row['id'].' - '.$row['username'].' - '.$row['image'].'</div>';
}
You could do with a good read up on both PHP and MySql but I'll give you a clue.
EDIT
$query = "SELECT * FROM `the_name_of_your_table` ORDER BY `user_id` DESC;";
if ($result = mysqli_query($link, $query)) {
/* fetch associative array */
while ($row = mysqli_fetch_assoc($result)) {
print $row["user_id"] . " - " . $row["username"] . "<BR>";
}
/* free result set */
mysqli_free_result($result);
}

Only one query instead of two

I have 2 tables, one is called post and one is called followers. Both tables have one row that is called userID. I want to show only posts from people that the person follows. I tried to use one MySQL query for that but it was not working at all.
Right now, I'm using a workaround like this:
$getFollowing = mysqli_query($db, "SELECT * FROM followers WHERE userID = '$myuserID'");
while($row = mysqli_fetch_object($getFollowing))
{
$FollowingArray[] = $row->followsID;
}
if (is_null($FollowingArray)) {
// not following someone
}
else {
$following = implode(',', $FollowingArray);
}
$getPosts = mysqli_query($db, "SELECT * FROM posts WHERE userID IN($following) ORDER BY postDate DESC");
As you might imagine im trying to make only one call to the database. So instead of making a call to receive $following as an array, I want to put it all in one query. Is that possible?
Use an SQL JOIN query to accomplish this.
Assuming $myuserID is an supposed to be an integer, we can escape it simply by casting it to an integer to avoid SQL-injection.
Try reading this wikipedia article and make sure you understand it. SQL-injections can be used to delete databases, for example, and a lot of other nasty stuff.
Something like this:
PHP code:
$escapedmyuserID = (int)$myuserID; // make sure we don't get any nasty SQL-injections
and then, the sql query:
SELECT *
FROM followers
LEFT JOIN posts ON followers.someColumn = posts.someColumn
WHERE followers.userID = '$escapedmyuserID'
ORDER BY posts.postDate DESC

How do I get a date from my database to show, only when certain conditions are met?

I am trying to get a date from my database, but only when certain conditions are met.
I want a table to populate with data from mySQL, only when the data is submitted under a users name. (i.e. this data is relevant to this user.)
This data has been saved as a TIMESTAMP.
$sql = "SELECT * FROM bug LIMIT 100";
$result = mysql_query($sql)or die(mysql_error());
while($row = mysql_fetch_array($result)){
$bdate = $row['bugDate'];
$bfor = $row['bugFor'];
$finduserid= mysql_query
("SELECT UserId FROM user WHERE userName='{$_SESSION['myusername']}'");
if($finduserid)
{
$getuserid = mysql_fetch_assoc($finduserid);
}
$findbdate =
mysql_query("SELECT bugDate FROM bug WHERE bugDate = '$bdate'
AND '$bfor' = '" . $getuserid['UserId'] . "'");
if($findbdate)
{
$getbdate = mysql_fetch_array($findbdate);
}
$bdatetime = new DateTime($getbdate['bugDate']);
$formattedbdate = date_format($bdatetime, 'd,M Y');
If anyone can help me I'd greatly appreciate it.
Obviously the security is terrible and I'm pretty sure this method would be the most inefficient way of doing what I'm trying to do, however I'm a noob and kind of learning by doing. If you have some noob friendly documentation on security and seeing this is making you cringe, feel free to post a link. Any help is greatly appreciated.
(Let me know if you need to know more and sorry if I didn't include it in the first place!)
EDIT: I got it working. I was doing it the most roundabout, ridiculous way anyone could come up with. Although I didn't use JOIN it sent me on the right path. Condensed 250 lines of pointless not working code down to 3-4 that will be obvious to everyone but me.
I selected the row where my session login equalled my loginName on the database.
$finduserid= "SELECT UserId FROM user WHERE userName='{$_SESSION['myusername']}'";
$runuserid = mysql_query($finduserid)or die(mysql_error());
while($getuserid = mysql_fetch_array($runuserid)){
$userid = $getuserid['0'];
}
I then, only Selected records that included my username (instead of everything and then trying to get rid of everything that didn't have my username in it.) -_- (Im an idiot.)
$sql = "SELECT * FROM bug WHERE bugFor = '$userid'";
$result = mysql_query($sql)or die(mysql_error());
Read up on JOINs.
I can't exactly tell what your code is supposed to do, or completely decipher your DB's schema, but the below query should get all bugs for the current user that were filed on the given date:
SELECT b.*
FROM bug b INNER JOIN users u
ON b.bfor = u.userID
WHERE u.userName = '{$_SESSION['myusername']}'
AND b.bugDate = '$bdate'

How to construct a more complex mysql query for optimization

I have this lovely piece of code that I want to optimize:
$result = mysql_query("select day from cities where name='St Charles'");
$row = mysql_fetch_assoc($result);
$day = $row['day'];
$result = mysql_query("select id,durability from goods_meta_data");
while($row = mysql_fetch_assoc($result)) {
mysql_query("delete from possessions where day_created<" . ($day-$row[durability]) . " and good_id=" . $row['id']);
}
It deletes rows from the table 'possessions' if the possession has expired. Whether or not the possession has expired is determined by values in the tables 'goods' and 'cities'.
Specifically, the age of the good = day-day_created, if the age of the good is more than its durability, then it is expired. (Every possession is a type of good, and every good has a unique durability.)
This code works, but I feel like this could be done in a single query.
The latency to the mysql server is particularly large, so doing this operation in less queries would be very beneficial.
How do I do that? Any ideas?
Also, if you can point me to any useful resources where I can learn about taking better advantage of relational databases in this manner, it would be helpful.
Assuming your first query returns a single result, then this should work:
DELETE p
FROM possessions p
INNER JOIN goods_meta_data gmd ON p.good_id = gmd.id
INNER JOIN cities c ON c.name = 'St Charles'
WHERE p.day_created < c.day - gmd.durability

Foreach or Inner join? -- that is the PHP question

I have 2 tables. One (artWork) with all the data I want to pull from, including 2 cols of id's. The other (sharedWork) has the same 2 id cols that are also in the first -- but none of the essential data I want to echo out. Objective: use the id's in both table to filter out row in the first (artWork). See below in the code what I tried that didn't work
I also tried to figure out an inner join that would accomplish the same. No luck there either. Wondering which would be the best approach and how to do it.
thanks
Allen
//////// Get id's first ///////////
$QUERY0="SELECT * FROM artWork WHERE user_id = '$user_id' ";
$res0 = mysql_query($QUERY0);
$num0 = mysql_num_rows($res0);
if($num0>0){
while($row = mysql_fetch_array($res0)){
$art_id0 = $row['art_id'];
}
}
$QUERY1="SELECT * FROM shareWork WHERE user_id = '$user_id' ";
$res1 = mysql_query($QUERY1);
$num1 = mysql_num_rows($res1);
if($num1>0){
while($row = mysql_fetch_array($res1)){
$art_id = $row['art_id'];
}
}
$art_id2 = array_merge($art_id0, $art_id1);
foreach ($art_id2 as $art_id3){
$QUERY="SELECT * FROM artWork WHERE art_id = '$art_id3' ";
// echo "id..".$art_id0;
$res = mysql_query($QUERY);
$num = mysql_num_rows($res);
if($num>0){
while($row = mysql_fetch_array($res)){
$art_title = $row['art_title'];
$art_id = $row['art_id'];
etc................and so on
.........to....
</tr>";
}
}
}
Don't query your database inside a loop unless you absolutely have to.
Everytime you query the database, you're using disk I/O to read through the database and return your record. Disk I/O is the slowest read on a computer, and will be a massive bottleneck for your application.
If you run larger queries upfront, or at least outside of a loop, you will hit your disk less often, improving performance. Your results from larger queries will be held in memory, which is considerably faster than reading from disk.
Now, with that warning out of the way, let's address your actual problem:
It seems you're trying to grab records from artWork where the user is the primary artist, or the user was one of several artists to work on a group project. artWork seems to hold the id of the primary artist on the project whereas shareWork is probably some sort of many-to-many lookup table which associates user ids with all art projects they were a part of.
The first thing I should ask is whether or not you even need the first query to artWork or if the primary artist should have a record for that art_id in shareWork anyway, for having worked on the project at all.
If you don't need the first lookup, then the query becomes very easy: just grab all of the users art_ids from shareWork table and use that to lookup the his or her records in the main artWork table:
SELECT artWork.*
FROM artWork
WHERE art_id IN
(SELECT art_id
FROM shareWork
WHERE user_id = $user)
If you do need to look in both tables, then you just add a check in the query above to also check for that user in the artWork table:
SELECT artWork.*
FROM artWork
WHERE
user_id = $user
OR art_id IN
(SELECT art_id
FROM shareWork
WHERE user_id = $user)
This will get you all artWork records in a single query, rather than.. well, a lot of queries, and you can do your mysql_fetch_array loop over the results of that one query and be done with it.

Categories