How to avoid the numerous calls to my DB? (MySQL + PHP) - php

With the following code I get all the pages I admin on Facebook using FQL. I do not print them though.
$PageNames = $facebook->api('/fql', array('q' =>
'SELECT name, page_id FROM page WHERE page_id IN (
SELECT page_id FROM page_admin WHERE uid=me() )'));
Previously, I have added in my DB the *page_id* of some of my pages. My goal is to show the pages that I have not added to my DB yet. It is working correctly and the code is below.
foreach($PageNames['data'] as $PageName) {
$investigate_id = mysql_query("SELECT page_id FROM pages WHERE page_id='"
.$PageName['page_id']."' LIMIT 1 ");
if(mysql_num_rows($investigate_id) == 0) {
echo $PageName['page_id'].$PageName['name'];
}
}
My problem/question is if somehow I can avoid the numerous DB calls because it makes the query for every page I admin. How can I achieve this?

<?php
$IDs = array();
foreach($PageNames['data'] as $PageName){
$IDs[] = $PageName['page_id'];
}
$investigate_id = mysql_query('SELECT page_id FROM pages WHERE page_id IN (\''.implode('\', \'', $IDs)).' LIMIT 1 ');
while($assoc = mysql_fetch_assoc($investigate_id)){
// iff
}
?>
Using WHERE col IN will make one query will all ID so
WHERE page_id IN (1,3,45,6,7,6,7,5,2,1,5,76) and it will do it in query, just make the loop after over the results and do whatever you want !

You may collect the IDs from results you got with FQL and then query DB for rows that exists in results to filter those present in DB from results...
$fql = <<<FQL
SELECT name, page_id FROM page WHERE page_id IN (
SELECT page_id FROM page_admin WHERE uid = me()
)
FQL;
// Get results from API
$pages = $facebook->api('/fql', array('q' => $fql));
// Collect pages for later usage by ID
$pagesByIds = array();
foreach($pages['data'] as $page){
$pagesByIds[$page['page_id']] = $page;
}
// Query DB for all pages that exists in results
$pagesIds = implode(',', array_keys($pageByIds));
$res = mysql_query("SELECT page_id FROM pages WHERE page_id IN ({$pageIds})");
while($pageRow = mysql_fetch_assoc($res)){
$pageId = $pageRow['page_id'];
// Remove pages that present in API results and DB
if (isset($pagesById[$pageId])) unset($pagesById[$pageId]); ;
}
// Display details for pages not existing in DB
foreach ($pagesByIds as $page){
echo "ID: {$page['page_id']}, Name: {$page['name']} \n"
}

Related

Have 2 queries and wondering if they can be combined

So i have 2 queries, I am trying to run one inside of a loop (unsuccessfully), but I'm thinking there might be a possibility that I can combine the 2 of them.
Table profile_posts
ID
post_title
post_body
user_id
post_date
Table profile_posts_likes
ID
likes
user_like_id
post_id
$baseURL = 'Data.php'; //Grab page for pagination
$id = $_GET['id']; //Grab id from link
$limit = 10; //Limit returns to 10
//Select statement that grabs results from profile_posts table
$postQuery = "SELECT * FROM profile_posts WHERE user_id = :id ORDER BY post_date DESC LIMIT $limit"; //First Query
// Count of all records
$rowCount = countRecords($conn, $id);
// Initialize pagination class
$paginationConfig = array(
'postID' => $id,
'baseURL' => $baseURL,
'totalRows' => $rowCount,
'perPage' => $limit,
'contentDiv' => 'postContent',
'link_func' => 'searchFilterProfile'
);
$pagination = new Pagination($paginationConfig);
$profilePost = $conn->prepare($postQuery);
$profilePost->bindParam(":id", $id);
$profilePost->execute();
if($profilePost->rowCount() > 0){
foreach($postDisplay as $row){
$likeQuery = "SELECT id, COUNT(likes) as likeCount, user_Like_id, post_id FROM profile_posts_likes WHERE post_id = :postID"; //Second Query
$likeQuery = $conn->prepare($likeQuery);
$likeQuery->bindParam(":postID", $row['id']); //Grab id from first query
$likeQuery->execute();
$postlikeQuery = $likeQuery->fetchAll();
if($likeQuery->rowCount() > 0){
//Display like buttons, when user clicks "Like" button, send data through Ajax
//and update page with "Liked"
}
}
}
What this does is displays the posts on the users profile page, and then when a user views their page, they can 'Like' the post or 'unlike it'...Using Ajax to update page
Now is there a way that I can combine those 2 queries together instead of running one inside of the loop. I tried tossing a WHERE EXISTS in there to combine the Select statements, but no luck.
Appreciate any help. Thanks in advance.
You may express your query using a join:
SELECT ppl.id, ppl.user_Like_id, ppl.post_id
FROM profile_posts_likes ppl
INNER JOIN
(
SELECT *
FROM profile_posts
WHERE user_id = :id
ORDER BY post_date DESC
LIMIT $limit
) pp
ON pp.id = ppl.post_id;
Selecting COUNT in the second query makes no sense, as you are not using GROUP BY.

Search list of Facebook friends

I am trying to search a user's Facebook friends list against entries in a gamers table in an application database.
The gamers table looks like id, name, points. Eg. g_id-234567, name-john Smith, points-45. In this table a person's id, is actually their Facebook id.
I am using the following code in my Codeigniter application with the Facebook php sdk to return list of friends for the logged in user.
$friends = $facebook->api('/me/friends');
foreach ($friends["data"] as $value) {
echo $value['id'];
}
This code is in my index function of my controller, and it successfully echos the ids of all the friends of the logged in user.
How do I check if any of my Facebook friends id matches that of any gamer g_id in my gamers table.
I want to get the list of gamers who are my Facebook friends, and order this list in descending order of points witha limit of 20. This is to get the top 20 Facebook friends gamers.
I would like to use this list of the logged in user's top 20 Faccebook friends in my view.
Try this (If you are using mysqli)
$id = -1;
$list = array();
$stmt = $mysqli->prepare("SELECT * FROM gamers where id = ? ORDER BY points DESC LIMIT 20");
$stmt->bind_param("i", $id);
foreach($friends["data"] as $value) {
$id = $value['id'];
$stmt->execute();
$res = $stmt->get_result();
array_push($list,$res->fetch_row());
}
I hope, $list should contain the list of all facebook gamers.
Alternatively, you can use :
$friends_set = '(';
foreach($friends["data"] as $value) {
$friends_set .= $value['id'].',';
}
$new_set = preg_replace('/,$/',')',$friends_set);
$res = mysql_query("SELECT * from gamers WHERE id IN $new_set ORDER BY points DESC LIMIT 20");
while($row = mysql_fetch_array($res,MYSQLI_ASSOC) {
//do your stuff
}
Inside last loop you may traverse list of facebook gamers.

slow results using while loop with mysql_fetch_array

I'm getting terribly slow results from the following code. I've been trying to troubleshoot it for hours but with no results. I've included only the relevant code.
Edit:
I am trying to select an id from a database and then use that id to get all the images associated with it. I am then narrowing that group of images down to one. Once I have that image I am resizing it through an external file.
I've tried removing various parts of the code to identify the problem and it seems as if the slow down is being caused by the second query but I am not sure why. Thanks for your help.
$getworks = mysql_query ("SELECT a_id from artists where display_works = '1' and active = '1' order by project_year desc, fullname desc");
while ($getworksrow = mysql_fetch_assoc($getworks)){
$totalimages=1;
$addstyle = "";
$id = $getworksrow["a_id"];
$getimages = mysql_query ("SELECT a_id, image_id from images where a_id = '". $id ."' order by position asc LIMIT 1");
$getimagesrow = mysql_fetch_assoc($getimages);
foreach ($getimagesrow as $getimagesrows){
extract($getimagesrow);
if($totalimages > 1){ $addstyle = 'style="display:none;"'; }
else {
$myimagename = "http://artist.com/$a_id/images/$image_id" . "_large.jpg";
list($width, $height, $type, $attr) = getimagesize("$myimagename");
$myimagename = "http://artist.com/artists/resize.php/$a_id/images/$image_id" . "_large.jpg?resize(157x2000)";
if($getworksrows["layout"] == "vert"){$pl = "_vertical";}else if($getworksrows["layout"] == "website"){$pl = "-s";}else if($getworksrows["layout"] == "video"){$pl = "_video";}else{$pl = "_horizontal";}
echo "<li class='thumbnail_container' $addstyle> <a class='thumbnail' href=\"../works$pl.php?a_id=" . $getworksrows["a_id"] . "\"><span><img src=\"$myimagename\" /></span>\n</a></li>\n";
}
$totalimages++;
}
}
It's a a big performance overhead to execute queries like this specially when parent query have large no. of records.
You should use join artists table with images table and get all data by single query.
Later on make 2D array of per artists and images. and loop according to 2D array to display data
Below is join query you should use:
SELECT * from artists as art
left join images as img on art.a_id=img.a_id
where display_works = '1' and active = '1'
order by project_year desc, fullname desc
In While make data array:
while ($getworksrow = mysql_fetch_object($getworks)){
$data['a_id']['img_id']=$getworksrow->image; //Make 2D array
........
........
}
looping and display data :
foreach($data as $id=>$images)
{
foreach($images as $val){
// Do your stuff for displaying data
}
}
So please do required changes.

Searching for unread posts in a database

Everytime a user reads a post, it assigns a cookie, eg.
set_cookies($id,'read',60*60*24);
But the problem is how do i select all the posts that hasn't been read by the user?
SELECT * from posts where (post is unread)
It doesn't require a login. Table structure:
ID | Content | Category
With your solution, you'd do something like this:
$ids = array();
if (isset($_COOKIES)) {
foreach ($_COOKIES as $cookie => $value) {
if (is_numeric($cookie) && $value == 'read') {
$ids[] = $cookie;
}
}
}
if (isset($ids[0])) {
$posts = implode(',',$ids);
$query = "SELECT * from posts where id in ({$posts})";
// Do the query
} else {
// no read posts.
}
But you should really look into storing your read variables differently.
I am assuming here that when user reads a post the id of the post read is stored somewhere. Let's for the moment assume that it is in the table read_posts that has a format:
UID | ID
In this case your query becomes:
SELECT * FROM posts WHERE ID NOT IN (SELECT id FROM read_posts WHERE uid = <user's id>);
If you only allow reading sequentially and store data in the same table the query becomes even simpler:
SELECT p.* FROM posts p, read_posts rp WHERE p.ID > rp.ID AND rp.UID = <user id>;
Syntax on this query might vary slightly but the general idea I think is clear.
If you can create a list of ids that have been read, yes:
SELECT *
FROM posts
WHERE ID NOT IN ($list_of_post_ids_that_have_been_read)

how to check current position in mysql

how can i check current number in mysql where....
my query is
$aid = 16;
$get_prev_photo = mysql_query("SELECT * FROM photos WHERE album_id='$aid' AND pic_id<'$picid' ORDER BY pic_id LIMIT 1");
$get_next_photo = mysql_query("SELECT * FROM photos WHERE album_id='$aid' AND pic_id>'$picid' ORDER BY pic_id LIMIT 1");
while i am getting current photo with following query
$photo = mysql_query("SELECT * FROM photos WHERE pic_id='$picid' LIMIT 1");
and getting total photos in album with following query
$photos = mysql_query("SELECT * FROM photos WHERE album_id='$aid'");
$total_photos = mysql_num_rows($photos);
now i want to check where i am and show it as Showing 1 of 20, showing 6 of 20 and so on...
now i want to check where i am actually...
i think you are referring to pagination, which can be achieved using LIMIT and OFFSET sql
decide the number of results you want per page, then select that many
create links like:
View the next 10
and dynamically change those every time
queries look ~like~
$offset=$_GET['view'];
SELECT * FROM table WHERE `condition`=true LIMIT 5 OFFSET $offset
this translates roughly as
select 5 from the table, starting at the 10th record
This is bad:
$photos = mysql_query("SELECT * FROM photos WHERE album_id='$aid'");
Because it grabs all the fields for the entire album of photos when all you really want is the count. Instead, get the total number of photos in the album like this:
$result = mysql_query("SELECT count(1) as total_photos FROM photos
WHERE album_id='$aid'");
if ($result === false) {
print mysql_error();
exit(1);
}
$row = mysql_fetch_object($result);
$total_photos = $row->total_photos;
mysql_free_result($result);
Now you have the count of the total number of photos in the album so that you can set up paging. Let's say as an example that the limit is set to 20 photos per page. So that means that you can list photos 1 - 20, 21 - 40, etc. Create a $page variable (from user input, default 1) that represents the page number you are on and $limit and $offset variables to plug into your query.
$limit = 20;
$page = $_POST['page'] || 1; // <-- or however you get user input
$offset = $limit * ($page - 1);
I'll leave the part where you code the list of pages up to you. Next query for the photos based on the variables you created.
$result = mysql_query("SELECT * FROM photos WHERE album_id='$aid'
ORDER BY pic_id LIMIT $limit OFFSET $offset");
if ($result === false) {
print mysql_error();
exit(1);
}
$photo_num = $offset;
while ($row = mysql_fetch_object($result)) {
$photo_num++;
$pic_id = $row->pic_id;
// get the rest of the variables and do stuff here
// like print the photo number for example
print "Showing photo $photo_num of $total_photos\n";
}
mysql_free_result($result);
I'll leave better error handing, doing something with the data, and the rest of the details up to you. But that is the basics. Also I did not check my code for errors so there might be some syntax problems above. To make a single photo per page just make $limit = 1.

Categories