Social timeline SQL logic - php

I am not experienced with MySQL genius so pardon me. I have 2 tables,
TABLE 1 contains column names: post_id (int, Auto Increment), post (varchar, user posts) and like (int) {like is incremented when a user likes the post e.g similar to facebook likes}
TABLE 2 contains column name: id (int, Auto Increment) and post_id(int, foreign key to TABLE 1), user_id(varchar, User who liked this post)
Now here is the tricky part for me, I want to select all posts from TABLE 1 and also indicate to the user which post has already been liked through TABLE 2 when a user requests for timeline, thus preventing the user from liking the the post again e.g how likes works on Instagram or any other social network i.e unlike if already liked.
What I tried using PHP and MySQL: Basically I retrieved all post from TABLE 1 based on the user retrieving a timeline and then I retrieved all data from TABLE 2 based on the user who needs the timeline, then I check to see if there is a match with TABLE 1's returned data and TABLE 2's returned data. With each returned post in the timeline I tag 1 to indicate in code the incoming post has been liked and 0 for not liked and then I display the appropriate UI flow to user in doing so I can make sure the user does not like the same post twice.
Selecting all from TABLE 2
SELECT * FROM `TABLE_2` WHERE `username` = :username
Selecting from TABLE 1
SELECT * FROM `TABLE_1` WHERE `reporter` IN (SELECT `destination_id` FROM `followers` WHERE `source_id` = :username)
UNION
SELECT * FROM `TABLE_1` WHERE `reporter` = :username
ORDER BY `created_at` DESC LIMIT 20
The above query returns a users timeline based on another logic and certain other factors
Now I compare both returned data from TABLE 1 and TABLE 2
if($likes != NULL)
{
$count = 0;
foreach($returnedtimeline["posts"] as $single)
{
if(array_search($likes[$count], $single) == "id")
{
$returnedtimeline["posts"][$count]["liked"] = 1;
$count++;
}else{
$returnedtimeline["posts"][$count]["liked"] = 0;
$count++;
}
}
But I believe there is a better way I can do this through one direct query than multiple queries because my methods has large disadvantages with time, amount of data and processing power of the server.

I believe you just want join in your select, to return columns from both tables at once. Something like:
select
post_id,
case when "Table 2".post_id is null then 0 else 1 end as UserHasLiked
from "Table 1"
left join "Table 2" on "Table 1".post_id = "Table 2".post_id
I'm not a MYSQL user, so the syntax may be a little off, but it should be pretty close I think.

SELECT DISTINCT *,
CASE WHEN likes.face_id = persona.face_id THEN '1' ELSE '0' END liked,
CASE WHEN dislikes.face_id = persona.face_id THEN '1' ELSE '0' END disliked,
CASE WHEN comments.face_id = persona.face_id THEN '1' ELSE '0' END commented
FROM persona, likes, dislikes, comments
RIGHT JOIN tagged ON tagged.phone_id = :pid WHERE persona.face_id = tagged.face_id
works like magic.

Related

What join to use

I have two tables, one for registered users and one to store votes.
We are logging in with registrants.id and registrants.zipcode. Once they vote their votes are inserted into the votes table, along with their Registration ID.
Im trying to right a select statement that returns a record that will select all the records for Matched ID and Zipcode, but the ID is not in the Votes.voter column. i have tried all kinds of variations of all the joins i can think of. is it something simple i am missing.
SELECT * FROM registrants
LEFT JOIN votes on registrants.id = votes.voter
WHERE registrants.id = 1 AND registrants.zipcode = 46706 and votes.voter <> 1
Perhaps a not exists query:
select * from registrants
where registrants.zipcode = '46706'
and not exists (select 1 from votes where registrants.id = votes.voter)

How to write IF ELSE statements in MySQL

I have tables posts and users
basically i want to query if the column privacy of posts table is 0 it means post is public and i want to show this to everyone. but if privacy column is 1,2,3,4 it means this post is only for users with ID 1, 2, 3 and 4
This is not a conditional problem it's a sql join through table association problem.
You need to create a join table that associates a post to a user. You can then use a join to select posts based upon their assignment to a user.
The SQL might look something like this
To select posts assigned to user ID = 4
SELECT * FROM `posts`
LEFT JOIN `posts_users` ON (`posts`.`id` = `posts_users`.`post_id`)
WHERE `posts_users`.`user_id` = 4;
You have also made the assumption that if a post has no users assigned to it, then it's a public post. That requires a check for NULL associations.
SELECT * FROM `posts`
LEFT JOIN `posts_users` ON (`posts`.`id` = `posts_users`.`post_id`)
WHERE `posts_users`.`user_id` IS NULL;
If you want to find both public and associated posts, then you use a logical OR to match both rules.
SELECT * FROM `posts`
LEFT JOIN `posts_users` ON (`posts`.`id` = `posts_users`.`post_id`)
WHERE `posts_users`.`user_id` = 4
OR `posts_users`.`user_id` IS NULL;

Using php and Mysql to Order by highest number and confirmation

Well I have this mysql table with numbers in one column and a confirmation boolean of 0 or 1 and I have about 1,000 rows so it's not something I can do manually but anyways...
I want to sort the row by highest value and grab the names of the first 5 people and put those 5 people in another table on a column and then set them to confirmed and continue until there's no one left in the table that isn't confirmed...
ex:
Name:Rank:Confirm
Bob:5000:0
James:34:0
Josh:59:1
Alex:48:0
Romney:500:0
Rolf:24:0
Hat:51:0
so when you run the code it will do the following:
Squad:Name1:Name2:Name3:Name4:Name5
1:Bob:Romney:Hat:Alex:James
(as you can see Josh was excluded and Rolf was too low)
And since Rolf is alone and there are no one else left, he wont be put into a team and will be left unconfirmed...
I'm not really pro at mysql so I was stumped on this and at most was capable of organizing the whole thing by rank and that's it ._.
edit:
The terrible attempt I had at this:
<?php
$parse = mysql_query("SELECT MAX(rank) AS rank FROM users AND confirm='0'");
mysql_query("Insert into squad (nameone)values($parse)");
mysql_query("Update squad set confirm = '1' where name = $parse");
?>
Assuming confirm will have only either 1 or 0.
CREATE TABLE table2 (id INT PRIMARY KEY AUTO_INCREMENT, name varchar(255));
CREATE PROCEDURE rank()
BEGIN
DECLARE count INT DEFAULT 1;
WHILE count > 0 DO
UPDATE table1 SET Confirm=2 WHERE Confirm=0 ORDER BY Rank DESC LIMIT 5;
INSERT INTO table2 (SELECT GROUP_CONCAT(Name) FROM table1 WHERE Confirm=2);
UPDATE table1 SET Confirm=1 WHERE Confirm=2;
SELECT count(*) FROM table1 WHERE Confirm=0;
END WHILE;
END;
Call the procedure rank() when ever you want
CALL rank();

select 3 rows from mysql table, then get each row's specific column

Select 3 rows from table1
Get a specific column data out of each row.
Then use that each column data obtained , to make a query again to get data from table2.
Store the data obtained in step 4 into a variable for each row.
Then put them in json array (table 1 , 3 rows + table 2's data(each of them).
I am building a rank table, it displays top 3 users with their rank name.
For example:
User1 has 2000 points , user 2 has 4000points , user 3 has 10k points , so the top 3 user is :
user 3 > user 2 > user 1
So , i want the php to go to 'users' table and get the top 3 members using this:
$query = mysql_query("SELECT * FROM users ORDER BY pts DESC LIMIT 3");
$rows = array();
while($r = mysql_fetch_assoc($query)) {
$rows[] = $r;
}
Table structure for 'user':
1.username(varchar)
2.pts(int)
After the rows are put into an array , how can i get 'points' for each of the row in that array.
Then go to 'rank' table to get their ranknames.
Table structure for 'rank':
1.rank(varchar)
2.pts(int)
Inside rank table there is 'pts' to let php choose compare which rank the user is at based on the points from each row of the array.
Normally i would use this if its only for 1 user , but for multiple users , im not sure:
$result = mysql_query("SELECT * FROM rank WHERE pts <= '$upts' ORDER BY pts DESC LIMIT 1")
or die(mysql_error());
Then after getting the rank for the top 3 users , php will now add the ranks to each of the user(row) in that array(of course , add it to the rank owner, not just simply place it in).
Then JSON encode it out.
How can i do this?
I am not sure if this is what you want. That is combine the two query into one query. Please take a look at http://sqlfiddle.com/#!2/ad419/8
SELECT user.username,user.pts,rank.rank
FROM user LEFT JOIN rank
ON user.pts <=rank.pts group by user.id
UPDATED:
For extracting top 3, could do as below;
SELECT user.username,user.pts,rank.rank
FROM user LEFT JOIN rank
ON user.pts <=rank.pts
GROUP BY user.id
ORDER BY pts DESC LIMIT 3
If i understand correctly, you need to get values from Rank and Users tables. In order to do that in just one query You need to add FK (Foreign Key) to the Rank table that points to a specific user in the Users table.
So you need to add userId to the Rank table and then you can run:
SELECT r.rank, u.points from users u,rank r where u.userId = r.userId
This is roughly what you need.
Not quite the answer to your exact question, but this might be of use to you: How to get rank using mysql query. And may even mean that you don't require a rank table. If this doesn't help, I'll check back later.
Use this query
$query = "SELECT
u.pts,
r.rank
FROM users as u
left join ranks as r
on r.pts = u .pts
ORDER BY pts DESC
LIMIT 3";
This will bring what you required without putting into an array
$rec = mysql_query($query);
$results = arrau();
while($row = mysql_fetch_row($rec)){
$results[] = $row;
}
echo json_encode($results);
It looks like what you're trying to do is retrieve the rank with the highest point requirement that the user actual meets, which isn't quite what everyone else is giving here. Fortunately it is easily possible to do this in a single query with a nice little trick:
SELECT
user.username,
SUBSTRING_INDEX(GROUP_CONCAT(rank.rank ORDER BY pts DESC),",",1) AS `rank`
FROM user
LEFT JOIN rank ON user.pts >= rank.pts
GROUP BY user.id
ORDER BY pts DESC
LIMIT 3
Basically what the second bit is doing is generating a list of all the ranks the user has achieved, ordering them by descending order of points and then selecting the first one.
If any of your rank names have commas in then there's another little tweak we need to add on, but I wouldn't have thought they would so I've left it out to keep things simple.

Can't figure out the system for "approve post once 10 users like it"

I have a voting system for articles. Articles are stored in 'stories' table and all votes are stored in 'votes' table. id in 'stories' table is equal to item_name in 'votes' table (therefore each vote is related to article with item_name).
I want to make it so when sum of votes gets to 10 it updates 'showing' field in 'stories' table to value of "1".
Here is a query I use to insert votes into database now (I was thinking to add something to it or create another query to sum vote_values of article user is voting on and see if they are > 10 if yes set showing = 1) :
$q = "INSERT INTO {$this->votes_table} (`vote_value`, `item_name`, `ip`) VALUES({$dir}, '{$story_id}', '{$ip}')";
Here is my database structure:
Stories table
Votes table
Try:
CREATE TEMPORARY TABLE tmp_ids SELECT s.id
FROM stories s
JOIN votes v ON v.item_name = s.id
WHERE s.showing != 1
GROUP BY s.id
HAVING SUM(v.vote_value) >= 10;
UPDATE stories SET showing = 1 WHERE id IN (SELECT id FROM tmp_ids)
// EDIT version on every vote
UPDATE stories s
SET s.showing = IF((SELECT SUM(vote_value) FROM votes WHERE item_name = ?) >= 10, 1, 0)
WHERE s.id = ?

Categories