Searching for unread posts in a database - php

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)

Related

Update a mysql table based on another. Complicated query

Short about my tables: I have 2 tables: content, users
content structure is something like:
id | title | cpc | user | active
users is:
id | user | monetos
Idea - I want to select contet.* rows which have content.active = 1 (n). Having this data, SELECT users.monetos WHERE users.id=content.user from previous query.
And now, by maximum (n) steps i decrement users.monetos value by content.cpc value
and on the moment when *users.monetos=0 or less than 0, i want to update content and SET active='0'*
By words, i want like to share users.monetos amount to each content entry (content.cpc for each). And there's no more users.monetos make the current content
entry inactive. And do this vor every content.user
What i'he done at this moment is shown below. I now it looks really bad, but i already don't know what to do. Count on you guys. Thank you.
$kak2 = array();
$rs16 = $connector->query("SELECT user FROM content WHERE active='1'");
while($rw16 = $connector->fetchArray($rs16))
{
$users_ids[] = $rw16['user'];
}
$user_info2 = $connector->fetchArray("SELECT monetos,id FROM users WHERE id IN (".implode(',',$users_ids).")");
while($user_info = $connector->fetchArray($user_info2))
{
$current_entry_info2 = $connector->query("SELECT cpc,id FROM content WHERE user='$user_info[id]' ORDER BY date DESC");
while ($current_entry_info = $connector->fetchArray($current_entry_info2))
{
$user_info['monetos']= $user_info['monetos'] - $current_entry_info['cpc'];
if($user_info['monetos'] = 0)
{
$updt = $connector->query("UPDATE content SET active='0' WHERE id='$current_entry_info[id]' LIMIT 1");
}
}
}
I think i have got the idea of what you are trying to do so have contructed a small code snippit which i think should do what you are after.
note this is untested code
/** get the cost of all content for all users **/
$query = "select b.id, sum(a.cpc) as cpc from content a
join users b on a.user= b.id
group by b.id where a.active = 1"
/** cycle each user **/
foreach($rows = $connector->fetchArray($query) as $row ) {
$menotos = $row['cpc'];
$query = "select id, cpc from content where user={$row['id']}"
/** cycle each users content **/
foreach($contents = $connector->fetchArray($query) as $content) {
$menotos -= $content['cpc'];
if($menotos <= 0) {
$disable[] = $content['id'];
}
}
if( isset($disable) ) {
$connector->query("update content set active=0 where id in(" . implode(',', $disable) . ")";
}
}

mysql return the total of rows for each user_id

$sql = "SELECT * FROM books LEFT JOIN users
ON books.readby=users.user_id WHERE users.email IS NOT NULL";
$result = mysql_query($sql);
while($row = mysql_fetch_array($result))
{
echo $row['readby']. " - read 10 books";
} //while ends
this is the code I have so far. I am trying to retrieve the number of books read by each user
and echo the results. echo the user_id and number of books he/she read
books table is like this : id - name - pages - readby
the row readby contains the user id.any ideas/suggestions? I was thinking about using count() but Im not sure how to go about doing that.
A subquery can return the count of books read per user. That is left-joined back against the main table to retrieve the other columns about each user.
Edit The GROUP BY had been omitted...
SELECT
users.*,
usersread.numread
FROM
users
/* join all user details against count of books read */
LEFT JOIN (
/* Retrieve user_id (via readby) and count from the books table */
SELECT
readby,
COUNT(*) AS numread
FROM books
GROUP BY readby
) usersread ON users.user_id = usersread.readby
In your PHP then, you can retrieve $row['numread'] after fetching the result.
// Assuming you already executed the query above and checked errors...
while($row = mysql_fetch_array($result))
{
// don't know the contents of your users table, but assuming there's a
// users.name column I used 'name' here...
echo "{$row['name']} read {$row['numread']} books.";
}
You can use count() this way:
<?php
$count = mysql_fetch_array(mysql_query("SELECT COUNT(`user_id`) FROM books LEFT JOIN users ON books.readby=users.user_id WHERE users.email IS NOT NULL GROUP BY `user_id`"));
$count = $count[0];
?>
Hope this helps! :)

How to get a session value from a second table?

I have two tables for the users; a login table and the user profile table.
I want to compare a value from 'userprofiletable' to another value from another table called posts. If the value is equal, it shows a list.
I have the following code. The problem is that it is not comparing the value in the posts table with the value of the session from user profile table.
Could someone help me please?
<?php
$limit = '5';
$dbreq = 'SELECT * FROM `posts` ORDER BY `pos` DESC';
$dbdata = mysql_query($dbreq);
while($dbval = mysql_fetch_array($dbdata))
{
if (($dbval['city'] == $_SESSION['student_city'])) { //checks for last 4 accomodation
if ($limit >= '1') {
echo '<tr><td>'.$dbval['title'].'</td></tr>';
$limit = $limit -'1';
}
}
}
?>
I also want to get the value of userprofiletable and post it in the posts table. For example, when somebody make a new post.
Your post is a bit unclear, but I think this is what you want:
<?php
$userid = 11542;//Sample uid. You will have to figure this out and set it.
$limit = 5;
$dbreq = "SELECT * FROM `posts` WHERE `userid`=".$userid." ORDER BY `pos` DESC LIMIT=".$limit.";";
$dbdata = mysql_query($dbreq);
while($dbval = mysql_fetch_array($dbdata))
{
if (($dbval['city'] == $_SESSION['student_city'])) { //checks for last 4 accomodation
echo '<tr><td>'.$dbval['title'].'</td></tr>';
}
}
?>
The question is not clear, but there could be two answers:
To reproduce your code, you can do in ONE sql query:
$dbreq = 'SELECT *
FROM `posts`
WHERE city="'.mysql_real_escape_string($_SESSION['student_city']).'"
ORDER BY `pos` DESC
LIMIT 4';
If, however, there are two tables, then you need "LEFT JOIN" linking the posts table to the userprofile table
$dbreq = 'SELECT p.*, u.*
FROM posts p
LEFT JOIN userprofiletable up ON p.UserID=up.UserID
WHERE up.city="'.mysql_real_escape_string($_SESSION['student_city']).'"
ORDER BY p.pos DESC
LIMIT 4';
(UserID in the table above is the name of the field in the posts table and userprofiletable that links the two.)

search for element in a php array

I've got
a users table named "members"
a rooms table named "rooms"
a table that associates the user id to the ids of the rooms "membersRooms"
I should write a loop that prints a dropdown for each user with all the rooms, but that adds the attribute "selected" to rooms associated with the user
What's wrong with this loop?
$members = mysql_query("SELECT * FROM members ");
$rooms = mysql_query("SELECT * FROM rooms");
while($member = mysql_fetch_array($members)){
echo("<select>");
$roomsOfUser = mysql_query("SELECT roomID FROM membersRooms WHERE userID=".$member["id"]);
$cuArray = mysql_fetch_array($roomsOfUser);
while($room = mysql_fetch_array($rooms)){
if(in_array($room["id"],$cuArray,true))
echo("<option selected='selected'>".$room["roomName"]."</option>");
else
echo("<option>".$class["roomName"]."</option>");
}
echo("</select>");
}
To make this a little easier on you, you could try utilizing left and right joins on your database. This would significantly reduce your server load and still allow you to do the same functionality.
I believe, if I'm reading your database structure right, that you'ld want something along the lines of:
SELECT members.id as memberID, rooms.id as roomID, rooms.roomName, membersRooms.roomID as memberRoom
FROM members
LEFT JOIN membersRooms
ON members.id = membersRooms.userID
RIGHT JOIN rooms
ON membersRooms.roomID = rooms.id
Then in PHP you should be able to just keep track of when your memberID changes, and when it does, start a new select. If I didn't totally bungle that SQL (which I might have) then the resulting rows should look something like:
memberID | roomID | roomName | memberRoom
1 1 foo 1
1 2 bar 1
2 1 foo 1
2 2 bar 1
So on your loop iteration you would use roomID and roomName to build your select, and if RoomID matched memberRoom then you would select that row.
$rooms query while is dead
while runs once time in while
put this $rooms = mysql_query("SELECT * FROM rooms"); query line
in first while
OK, so you need information from 3 tables - members, rooms, and membersRooms. The rows from members and membersRooms line up 1:1, so we can get both of those with 1 query.
This method will minimize the number of queries needed - if you ever see yourself querying the database in a loop, ask yourself if there's a better way.
$member_query = mysql_query("SELECT * FROM members LEFT JOIN membersRooms ON (members.id = membersRooms.userID)");
$room_query = mysql_query("SELECT * FROM rooms");
$rooms = array();
while ($room = mysql_fetch_assoc($room_query))
$rooms[] = $room;
while ($member = mysql_fetch_assoc($member_query)) {
echo '<select>';
foreach($rooms as $room) {
echo "<option value='{$room['roomID']}' ";
if ($member['roomID'] == $room['id'])
echo 'selected="selected"';
echo ">{$room['roomName']}</option>";
}
echo '</select>';
}
It's worth noting that if members:rooms is a 1:many relation, you don't need to use a third table to join them - just add a roomId to members, and you're fine.

Merging data from two different data sets (Facebook & MySQL)

I'm wondering if this is the best way to tackle this issue. I am merging a Facebook users friends data, (from facebook - returns a multi array) with the votes from the users in that list that voted (from MySQL).
This is how I accomplished this. I'm a junior developer and looking for help on making my code as optimized as possible.
public function getFriendVotes(){
global $facebook;
// Get The users friends that use this app from facebook
$friends = $facebook->api_client->fql_query(
"SELECT uid, first_name, last_name
FROM user
WHERE uid IN (SELECT uid2 FROM friend WHERE uid1=$this->user)"
);
// Create an array of just the ids
foreach($friends as $friend){
$userids[] = $friend['uid'];
}
// Create a string of these ids
$idstring = implode(",", $userids);
// Get the votes from only the users in that list that voted
$result = $this->db->query(
"SELECT vote, userid FROM user_votes WHERE userid IN ($idstring)"
);
// Create a new result set (multi array). Include the data from the first
// Facebook query, but include only those who voted and append their votes
// to the data
$row = $result->fetch_assoc();
foreach($friends as $friend){
if($row['userid'] == $friend['uid']){
$return[$count] = $friend;
$return[$count]['vote'] = $row['vote'];
$row = $result->fetch_assoc();
$count++;
}
}
return $return;
}
I asume that fql_query does support mysql syntax and it would be more efficient to use LEFT JOIN instead creatig extra query, here is my version of your code:
public function getFriendVotes(){
global $facebook;
// Get The users friends that use this app from facebook
$friends = $facebook->api_client->fql_query("
SELECT DISTINCT u.uid,u.first_name,u.last_name
FROM user AS u
LEFT JOIN friend AS f ON uid=uid2
WHERE f.uid1='{$this->user}'
");
$arrayUsers = array();
// Create an array of just the ids
foreach($friends as $v){
$arrayUsers[$friend['uid']] = $v;
}
unset($friends);
// Create a string of these ids
$idstring = implode(",", array_keys($arrayUsers));
// Get the votes from only the users in that list that voted
$result = $this->db->query(
"SELECT vote, userid FROM user_votes WHERE userid IN ({$idstring})"
);
$result = array();
// Create a new result set (multi array). Include the data from the first
// Facebook query, but include only those who voted and append their votes
// to the data
while($v = $result->fetch_assoc())
{
if(isset($arrayUsers[$v['userid']])
{
$arrayUsers[$v['userid']] = $v['vote'];
$result[] = $arrayUsers[$v['userid']];
unset($arrayUsers[$v['userid']], $v);
}
}
return $return;
}
I can't tell you how your code would perform without measuring and testing. I would look for other issues with your code, that would make it a bit more readable/maintanable. For example:
Create smaller methods.
Inside the main method , I see some chunks of code that are well commented. Why not create a method instead of making a huge comment in the main method?
For example:
// Get The users friends that use this app from facebook
$friends = $facebook->api_client->fql_query(
"SELECT uid, first_name, last_name
FROM user
WHERE uid IN (SELECT uid2 FROM friend WHERE uid1=$this->user"
);
return $friends;
Would make an interesting
functin get_users_friends_from_facebook($facebook){
// Get The users friends that use this app from facebook
$friends = $facebook->api_client->fql_query(
"SELECT uid, first_name, last_name
FROM user
WHERE uid IN (SELECT uid2 FROM friend WHERE uid1=$this->user"
);
return $friends;
}
In the same manner,
// Get the votes from only the users in that list that voted
$result = $this->db->query(
"SELECT vote, userid FROM user_votes WHERE userid IN ($idstring)"
);
Is a good candidate to
function get_votes_from_voters(){
// Get the votes from only the users in that list that voted
$votes = $this->db->query(
"SELECT vote, userid FROM user_votes WHERE userid IN ($idstring)"
);
}
Give variables meaningful names to the context.
$return isn't a good name. Why don't you name it $users_votes for example?
Try to keep the naming convention of your plataform.
Check the apis you're using. Are they using camelCase? Are they using underscores? Try to keep with your libraries and plataform conventions. Check this topic for a good reference.
And welcome to SO. Your code is fine. Try to read some OO principles, you could even cut more lines of your code. All the simple advices I wrote here are avaiable in a great book named Code Complete.
I took points from all your comments and rewrote this method as below. Thanks for all the great input.
public function getAppUserFriends(){
global $facebook;
return $facebook->api_client->fql_query(
"SELECT uid, first_name, last_name
FROM user
WHERE uid IN (SELECT uid2 FROM friend WHERE uid1=$this->user)
AND is_app_user;"
);
}
public function getFriendVotes(){
// Get the users friends that use this app
$friends = $this->getAppUserFriends();
// Create an array with the ids as the key
foreach($friends as $v){
$arrayFriends[$v['uid']] = $v;
}
// Create a string of these ids
$idString = implode(",", array_keys($arrayFriends));
// Get the votes from only the users in that list that voted
$result = $this->db->query(
"SELECT vote, userid
FROM user_votes
WHERE pollid=$this->poll
AND userid IN ($idString)"
);
// Pluck out user data from facebook array where the user has voted
// and add the vote to that array
while($row = $result->fetch_assoc()){
$friendsVotes[$row['userid']] = $arrayFriends[$row['userid']];
$friendsVotes[$row['userid']]['vote'] = $row['vote'];
}
return $friendsVotes;
}
Are you having performance troubles in this method? Because unless you are, there's no need to optimize it.
Code first, profile the code, and then optimize where it does the most good.
$friends = $facebook->api_client->fql_query(
"SELECT uid, first_name, last_name
FROM user
WHERE uid IN (SELECT uid2 FROM friend WHERE uid1=$this->user"
);
could probably be shortened to
$userids = $facebook->api_client->fql_query(
"SELECT uid
FROM user
WHERE uid IN (SELECT uid2 FROM friend WHERE uid1=$this->user)"
);
because the uid is the only thing you seem to be using from fb
It was a little hard for me to tell what you are trying to do, but you might consider looking at PHP's array_intersect (and its cousins).
A = {1:'fred', 2:'bob'}
B = {1: 2, 3: 0}
C = array_intersect( array_keys(A), array_keys(B) )
D = {}
foreach (C as c) {
D[c] = (A[c], B[c])
}
The syntax is off there but I hope it leads you in the right direction.

Categories