Select records from table1 depending on table2 - php

I am trying to build a project where you can like other people's pictures, and when the other person likes your picture too, you have a match. Like the Tinder app if you know.
Now, I fetch 1 photo like so:
SELECT id, picture_path, profile_picture, username
FROM tusers
WHERE profile_picture IS NOT NULL
AND settings LIKE '1,%'
AND sex = :sex
AND last_visit BETWEEN CURDATE() - INTERVAL 21 DAY AND CURDATE()
AND dob BETWEEN :dob - INTERVAL 5 YEAR AND :dob2 + INTERVAL 5 YEAR
LIMIT 1
However, if you've already LIKED or PASSED someone's photo, I don't want to show it to you again. I am not sure how to do this part yet (right now, I have alreadyLiked() and alreadyPassed() functions and I am only doing a header("Location") redirect if they return true, but that will fail when you have liked/passed all the photos).
I have another table with these columns: id, user1_id, user2_id, liked, passed, matched
When you like or pass a picture, a 1 is inserted in the corresponding column.
user1_id is your ID. user2_id is the other person's ID.
Knowing the above information, what kind of query (or logic) would you use to make sure that you only show the right people (that you haven't liked or passed already) ?

suppose you have 2 tables
usr
id username
1 a
2 b
3 c
4 d
liked
id user1 user2 liked
1 1 4 1
2 1 3 1
assuming your id is 1 , from table liked it seems you have liked c,d . since 1(a) is your own id you need only b as output, your query goes as below
SELECT *
FROM usr
WHERE id NOT
IN (
SELECT user2
FROM liked
WHERE user1 =1
)
and id!=1
assuming 1 will come from session

You can use mysql join to get data from one table based on the another
In the upper case you can have join on the first tables id with the other tables user1_id, user2_id putting where clause on the liked, passed, matched
To know more about mysql joins
Try this as join is much better than a inner query suggested by ersumit $loggedINuser_id='2';//take from session $sql="SELECT tu.id, tu.picture_path, tu.profile_picture, tu.username FROM tusers tu LEFT JOIN secondtable st ON tu.id=st.user2_id WHERE tu.profile_picture IS NOT NULL AND tu.settings LIKE '1,%' AND tu.sex = :sex AND tu.last_visit BETWEEN CURDATE() - INTERVAL 21 DAY AND CURDATE() AND tu.dob BETWEEN :dob - INTERVAL 5 YEAR AND :dob2 + INTERVAL 5 YEAR AND st.user1_id != '".$loggedINuser_id."' LIMIT 1";

Related

How to select particular column from table if another column includes all the set of requested values?

I have a table in MySQL named table1 which has three columns id, user_id(foreign_key) and destination_id(foreign_key). One user can have multiple destinations.
E.g Table1
id user_id destination_id
1 10 2
2 5 3
3 10 4
4 10 5
5 9 10
6 5 12
7 8 2
I get a request from the client side in PHP script; the request includes destination ids in an array.
E.g. $request = array('destination_id' => [2,4,5]);
I just want to get all the user_id from table1 if and only if the particular user_id contains all requested destinations.
I tried to achieve this using 'IN' operator.
i.e.
SELECT user_id FROM table1 WHERE destination_id IN ($requestedDestinationsInCommaSeparatedString)
It gives row including user_id 8 along with user_id 10 but I just need user_id 10. I just wanted to know the concept regarding the solution to the following problem. I am a beginner in SQL, any help would be very appreciable. Thanks.
You can check that a user_id refers to all requested destination by grouping and counting the destinations.
SELECT user_id
FROM table1
WHERE
destination_id IN (2,4,5)
GROUP BY
user_id
HAVING count(*) = 3
-- count must be the number of elments in (2,4,5)
For doing so, the field combination of user_id and destination_id must be unique over all records.
The only thing I can think of is to use multiple subselects and build the query string in PHP.
So for your specific example the SQL-Query-String generated should be
SELECT user_id
FROM table1
WHERE user_id IN
(SELECT user_id FROM table1 WHERE destination_id = 2)
AND user_id IN
(SELECT user_id FROM table1 WHERE destination_id = 4)
AND user_id IN
(SELECT user_id FROM table1 WHERE destination_id = 5)
GROUP BY user_id
I think programming the function which generates the middle part for you shouldn't be too hard.

MySql Statement across different rows

Im trying to query a wordpress mySQL database where the values pertaining to each user is spread across different rows (only god knows why they did it that way, why didnt they just put all the user information on one row)
For example
ID USER_ID FIELD_ID VALUE
1 1 2 my name is paul smith
2 1 3 books
3 1 4 loggedin
4 1 5 state=busy
5 2 2 my name is big boy
5 2 3 pens
6 2 4 offline
7 2 5 state=idle
here you can see each row has a different meaning based on the FIELD_ID for the same user
FIELD_ID=2 contains the user name
FIELD_ID=3 contains mean what they bought
FIELD_ID=4 means logged in
FIELD_ID=5 is busy or idle
I need to make ONE query that will return all users that are LOGGED IN and STATE=IDLE and bought BOOKS (or bought some other item like pens whatever they want to search for)
so i started off with this php statement
$find="pens";
$q = "SELECT * FROM table
WHERE FIELD_ID='4' AND VALUE='loggedin'
AND FIELD_ID='5' AND VALUE='idle'
AND USER_ID IN
(SELECT USER_ID FROM table WHERE FIELD_ID ='3' AND VALUE LIKE '%$find%')
But i dont think this will work because how can
FIELD_ID = '4' AND VALUE='loggedin' AND FIELD_ID='5' AND VALUE='idle' all at the same time because they are on different rows.
Does anybody know how to make ONE mySQL statement to do it?
you could use a self join
SELECT distinct a.user_id
FROM table a
inner join table b on a.user_id = b.user_id and b.field_id = 5 and b.value='idle'
inner join table c on a.user_id = c.user_id and c.field_id = 4 and c.value = 'loggedin'
where a.field_id=3 and a.value='BOOK'

Selecting N rows from each group in MYSQL

I need to search for the updates sent by the friends of a giving user.
There is a table called friendship. It has a column called profile1 and another one called profile2. It represents the friendship between two users in this websystem, and a friendship is the presence of two giving ids, no matter in what position. So the profile with id 1 may have 2 friends, profile with id 2 and with id 3 as following:
friendship
profile1 profile2
1 2 <--
3 1 <--
2 5
...
Now I want to search for the updates sent by some user's friends. There is this table update
update
id content time profile
1 A text ... 2
2 A text ... 2
3 A text ... 3
4 A text ... 2
5 A text ... 3
6 A text ... 2
7 A text ... 10
8 A text ... 11
If my profile/user is identified by the id 1, and it has only 2 friends (the profiles identified by id 2 and 3) and also I need my search to return only 2 results by each user, my SELECT has to return updates 1,2,3 and 5.
Preferably updates should be grouped by its author and it would be great if I could set the number of different profiles to be considered in this search (for example, if profile 1 had 10 friends and I wanted only updates from 3 profiles, the most recent must appear first).
Do you know how can I achieve this??
thank you very much!
#EDIT
This returns all updates sent by friends of profile 1. But i'm not sure whether or not i'm in the right direction
SELECT u.*
FROM `update` u
INNER JOIN friendship f1 ON f1.profile1 = u.author
WHERE f1.profile2 =1
UNION
SELECT u.*
FROM `update` u
INNER JOIN friendship f2 ON f2.profile2 = u.author
WHERE f2.profile1 =1
If you are willing to do it in two queries, you can do it like this. First, get three profiles who have most recently posted based on your constraints:
-- Get the three latest updated profiles from here.
-- (we can't use a CTE because MySQL doesn't support
-- them yet).
SELECT DISTINCT p.profile FROM
(
SELECT ui.profile, ui.time FROM
(
SELECT u.profile, u.time
FROM `update` u
INNER JOIN `friendship` f ON f.profile2 = u.profile
WHERE f.profile1 = 1
UNION ALL
SELECT u.profile, u.time
FROM `update` u
INNER JOIN `friendship` f ON f.profile1 = u.profile
WHERE f.profile2 = 1
) ui ORDER BY ui.time DESC
) p LIMIT 0, 3;
From that query, get the three profile IDs out and put them in place of <id1>, <id2> and <id3> in the following query
-- Use a union to get the result set back
(SELECT a.content, a.time, a.profile FROM `update` a
WHERE a.profile = <id1>
ORDER BY a.time DESC
LIMIT 0, 2)
UNION ALL
(SELECT a.content, a.time, a.profile FROM `update` a
WHERE a.profile = <id2>
ORDER BY a.time DESC
LIMIT 0, 2)
UNION ALL
(SELECT a.content, a.time, a.profile FROM `update` a
WHERE a.profile = <id3>
ORDER BY a.time DESC
LIMIT 0, 2);
If you get less than three profiles back, either remove parts of the query in your PHP code, or set the WHERE clause to something like 0 so it always evaluates to fault (assuming you don't have a profile ID of zero)
The 2 in the limit clauses above can be changed if you want more or fewer results per profile.
Sample SQL fiddle: http://sqlfiddle.com/#!2/22e57/1 (updated fiddle to make the content more meaningful and to use times)
I would suggest doing a series of queries for each author within one transaction, that way there would not be a need for grouping - you could simply append results together outside of your SQL.
SELECT * FROM `update` WHERE
profile IN (SELECT profile2 FROM `friendship` WHERE profile1=1) OR
profile IN (SELECT profile1 FROM `friendship` WHERE profile2=1);
try this sqlFiddle
SELECT T1.profile,T1.content,T1.time
FROM
(SELECT UPD.profile,UPD.content,UPD.time,
IF (#prevProfile != UPD.profile,#timeRank:=1,#timeRank:=#timeRank+1) as timeRank,
#prevProfile := UPD.profile
FROM
(SELECT UP.profile,UP.content,UP.time
FROM
(SELECT profile,max(time) as latestUpdateTime
FROM friendship F INNER JOIN updates U
ON (F.profile1 = 1 AND U.profile = profile2) /* <-- specify profile on this line */
OR(F.profile2 = 1 AND U.profile = profile1) /* <-- specify profile on this line */
GROUP BY profile
ORDER BY latestUpdateTime DESC
LIMIT 3 /* limit to 3 friends profiles that have the most recent updates */
)as LU
INNER JOIN updates UP
ON (UP.profile = LU.profile)
ORDER BY profile,time DESC
)as UPD,(SELECT #prevProfile:=0,#timeRank:=0)variables
)T1
WHERE T1.timeRank BETWEEN 1 AND 2 /* grab 2 lastest updates for each profile */
ORDER BY T1.time DESC
in my example, profile id 1 has more than 3 friends, but i am only grabbing 3 friends that made the most recent updates.
explanation of above query.
LU grabs 3 profiles that are friends with profile id 1 that made the latest updates.
UPD grabs all contents that belong to these 3 friends.
T1 returns the contents along with a timeRank number for each content in order from 1 counting upward order by time DESCENDING for each profile
and finally the WHERE we only grab 2 content updates for each profile
then we finally ORDER these updates based on TIME starting from most recent.

Getting next timestamp in MySQL

I would prefer to get this done in MySQL.
Table:
tracker | user_id | timestamp | action
1 1 1234 1
2 2 1236 9
3 1 1237 2
I need to find all users who had the action of 1, and subtract the timestamp from their next action. Meaning, User 1's 1234 timestamp will be subtracted from his 1237 timestamp.
The idea is to calculate how long the user spent at action 1 until they went somewhere else.
Getting the first timestamp is easy. One idea is to record the tracker value, and then do a subquery for where user_id pops up again with a tracker higher than the first. In the example: WHERE user_id = 1 AND tracker > 1
Is there a more optimal solution?
Probably this helps you. This will join to all future actions
SELECT t1.*,
t2.`timestamp` - t1.`timestamp`
FROM table t1
JOIN table t2
ON t1.user_id = t2.user_id
AND t2.tracker > t1.tracker
WHERE t1.`action` = 1;
you probably want to extend to add also a condition to get the next one only.
this is some ad-hoc query, and can't precisely tell if will work or not
This is suppose to select only the next one for that user.
SELECT t1.*,
t2.`timestamp` - t1.`timestamp`
FROM table t1
JOIN table t2
ON t1.user_id = t2.user_id
AND t2.tracker = (SELECT Min(tracker)
FROM table t3
WHERE t3.user_id = t1.user_id
AND t3.tracker > t1.tracker)
WHERE t1.`action` = 1;

SQL query - How to display points in the last 24 hours?

I'm building a website with points system, similar to Stackoverflow;
This is the code I'm using to display top users (for all time):
SELECT id, username, active, points
FROM users
WHERE active='1'
ORDER BY points DESC
But how can I show the top users in 24 hours (also points)?
You would have to make a special table that would record when (and how many) points the user received.
EDIT
E.g. table points
user_id time awarded_points
-------------------------------------
1 1298745681 10
...
Then you just ask for the points awarded today with WHERE time > UNIX_TIMESTAMP(CURDATE()) or in the last 24 hours WHERE time > UNIX_TIMESTAMP()-24*3600.
Example use:
SELECT u.id, u.username, u.active, SUM(p.awarded_points) AS points
FROM points AS p
LEFT JOIN users AS u ON u.id = p.user_id
WHERE time > UNIX_TIMESTAMP(CURDATE())
AND u.active = '1'
GROUP BY p.user_id
ORDER BY points DESC
I'd also suggest adding a LIMIT to the query, especially if your site grows big.
Your need another table, where all users activites/points would be write
And than join with this table, and condition to 24h
Add a table recording the points each user receives and when with a foreign key relation to the users table
For example a table named points with the following columns
userid (FK to users table)
datetimeallocated
numberofpoints
other columns of interest e.g. user who allocated the points etc
You then need to query this table e.g.
SELECT SUM(numberofpoints), userid
FROM points
WHERE datetimeallocated >= DATE_SUB(CURDATE(), INTERVAL 1 DAY)
GROUP BY userid
ORDER BY SUM(numberofpoints) DESC

Categories