Join with condition with different column - php

I have following two tables :
user_profile
id | name | email | phone
1 | Rahul |r#gmail.com |1234567890
2 | Rohan |r1#gmail.com |1234567890
3 | Mohan |m#gmail.com |1234567890
user_request_table
id | from_user_id|to_user_id|status
1 | 1 | 2 | 2
2 | 3 | 1 | 2
Here status
0 = Request is cancel,
1 = request is pending,
2 = request accepted
I have following section to display :
Find a friend
Here I need to display suggetion for friend. I need to display all record from user_profile table but user should not be a friend(status should not be 2) or request should not be pending(status should not be 1).
So if I logged in as Rohan(id : 2) it should suggest me Mohan as friend suggestion.

Would this work:
SELECT
u.*
FROM
user_profile u
LEFT JOIN user_request_table r ON u.id=r.to_user_id AND r.from_user_id = <your_logged_in_user_id>
WHERE
r.status NOT IN (2,1) --filter pending and accepted here ;

So you want those records in user_profile table that do not have a record in user_request table where user is either from_user_id or to_user_id. The pattern is to do a left join to user_request and filter out those where user_request.id is null:
select
p.*
from
user_profile as p
left join user_request as r on
(
(p.id = r.from_user_id and r.to_user_id = {id})
or
(p.id = r.to_user_id and r.from_user_id = {id})
)
and r.status in (1,2)
where
r.id is null
and p.id <> {id}
;
with {id} a parameter for the user you want to suggest friends for.

First get all possible pairs from the user_profile table. Next filter through all the pairs and eliminate the unqualified using data from the user_request_table. It will get all the eligible (from_user , to_user)pairs.
select u1_id as fromuser,u2_id as touser
from
(select distinct u1.id as u1_id,u2.id as u2_id from user_profile u1 cross join user_profile u2 where u1.id!=u2.id) all_pair
where not exists
(select from_user_id ,to_user_id from user_request_table where status>0 and (
((u1_id=from_user_id) and(u2_id=to_user_id)) or ((u1_id=to_user_id) and(u2_id=from_user_id))
)
)
;
The result set looks like this:
fromuser, touser
3 2
2 3

This solution is for MSSQL SERVER, you can modify as per your preferred server
Pass your logged in id to declared variable
DECLARE #LoginId AS INT
SET #LoginId=2 /*here I passed logged in id as 2*/
SELECT * FROM user_profile up
WHERE 1=1 and id<>#LoginId
AND id NOT IN (SELECT from_user_id FROM user_request_table WHERE to_user_id=#LoginId and STATUS in(1,2))
AND id NOT IN (SELECT to_user_id FROM user_request_table WHERE from_user_id=#LoginId and STATUS in(1,2))

Related

MySQL joining tables and returning the latest row from the second table when the comparison is made between identical values

I have table 1: users
id | name |
1 | john |
2 | garry|
3 | sam |
And table two called posts:
id | user_id | title | posted
1 | 1 | Something | 1551128761
2 | 1 | Else | 1551128761
3 | 3 | Some Title | 1551122745
4 | 2 | Demo Title | 1551129777
5 | 3 | Something | 1551126793
user_id in the second table is the id of the user in the first table
I need to get the latest post out of the table and i'm doing that currently by using this query:
SELECT u.id, u.name, p.title
FROM users AS u
LEFT JOIN posts AS p
ON p.user_id= u.id
WHERE p.posted = ( SELECT MAX(posted) FROM posts WHERE user_id = u.id )
ORDER BY u.id
LIMIT 15
But the problem with this query is that if the timestamp is the same for the same user (in this example for user with user_id 1 the timestamp is the same) i'm getting both of those rows instead of just the latest one(the latest one has the highest id)
Try this MySQL query:
SELECT u.id,
u.name,
p.title
FROM users AS u
JOIN posts AS p
ON p.id = (SELECT pi.id
FROM posts AS pi
WHERE pi.user_id = u.id
ORDER BY pi.id DESC
LIMIT 1);
Tested and works fine. Here is a demo: DBFiddle
To speed up select query, consider adding indexes
ALTER TABLE posts ADD INDEX(user_id);
ALTER TABLE posts ADD INDEX(posted);
One option using id column from posts table as following. This is assuming id is going to be different for each post record is posts table. Demo here
SELECT u.id, u.name, p.title,p.posted
FROM users AS u
LEFT JOIN posts AS p
ON p.user_id= u.id
WHERE (p.posted,p.id) = ( SELECT MAX(posted),MAX(id) FROM posts WHERE user_id = u.id )
ORDER BY u.id
How about restructuring the query slightly?
SELECT posts.title, users.id, users.name
FROM posts, users
WHERE posts.user_id = users.id
ORDER BY posts.posted DESC, posts.id DESC
LIMIT 1
Essentially selecting from posts, ordering by the posted timestamp and secondly the id of the post in descending order in case timestamp is the same.

Or condition in INNER JOIN

I have a table structured as follows (points):
id1 | id2 | p1 | p2
1 3 5 7
3 1 2 4
1 2 1 7
And another table strucuted as follows (users):
id | name
1 User1
2 User2
3 User3
So now, I need a query that specifing an ID (for example 3), the query check that the ID appears in the column id1 and id2, and if it appears in one of the two columns, it gives me back the user name with id1 and id2 from the rows selected. So, for example if I specific the ID 3, the query give me back:
name1 | name2 | p1 | p2
User1 User3 5 7
User3 User1 2 4
I tried various solutions but no way to do it, I think that I need an OR condition in the INNER JOIN but I don't know if it's possible and if it's the solution.. I didn't find nothing here.
I mean something like:
INNER JOIN users ON (users.id = points.id1) || (users.id = points.id2)
Any solution for that? Thanks
Join the user table twice:
SELECT u1.name, u2.name, p.p1, p.p2
FROM points p
JOIN users u1 ON u1.id = p.id1
JOIN users u2 ON u2.id = p.id2
WHERE u1.id = 3 OR u2.id = 3
Use case statement it will give you all matching value not need restricted for one or two values
CREATE TABLE points (id1 int(2), id2 int(2), p1 int(2), p2 int(2));
INSERT INTO points VALUES(1,3,5,7);
INSERT INTO points VALUES(3,1,2,4);
INSERT INTO points VALUES(1,2,1,7);
CREATE TABLE users (id int(2), name char(23));
INSERT INTO users VALUES(1,'user1');
INSERT INTO users VALUES(2,'user2');
INSERT INTO users VALUES(3,'user3');
SELECT (CASE WHEN u.id = p.id1 THEN u.name END) AS name1,
(CASE WHEN u1.id = p.id2 THEN u1.name END) AS name2,
p1, p2
FROM points p
INNER JOIN users u ON (u.id = p.id1)
INNER JOIN users u1 ON (u1.id = p.id2);

How to join tables based on the column value in a table

I have the table news_feed in which all of my different types of activities data will be stored like admin activities, user activities, company activities etc. The table format looks like:
news_id | type | admin_id | user_id | company_id
1 | admin | 2 | 3 | 0
2 | user | 3 | 4 | 1
3 | company | 0 | 1 | 2
Suppose a user with an id 1 has liked the company which has id 2 then the record will be inserted like
4 user 0 1 2
And I'm listing them in my module and the listing is perfect. But suppose if the company id 2 doesn't exist or if it is inactive, then the news_feed block in listing getting empty. What I want to do is:
If the type is company then JOIN the company table while select listing with condition for status as active
If the type is user then JOIN the user table while select listing with condition for status as active
Well you can use UNION for this issue
SELECT t.column1, t.column2, t.column3
FROM my_table t INNER JOIN company_table c
ON t.company_id = c.id
WHERE c.active=1 AND t.type = "company"
UNION
SELECT column1, column2, column3
FROM my_table t INNER JOIN user_table u
ON t.user_id = u.id
WHERE c.active=1 AND t.type = "user"
Just to add, to increase the efiiciency use UNION ALL rather than UNION (or UNION DISTINCT) as UNION requires internal temporary table with index (to skip duplicate rows) while UNION ALL will create table without such index, but keep in mind it will skip the repeated data.
But more optimized way to do a Conditional Join in MySQL by using a INNER JOIN
SELECT t.column1, t.column2, t.column3
FROM my_table t
INNER JOIN company_table c
ON (t.company_id = c.id AND t.type = "company" AND c.active=1)
INNER JOIN user_table u
ON (t.user_id = u.id AND t.type = "user" AND u.active=1);

Slow query using "where in" and "order by select count"

I want to show post from users that specified user is followed and i have two tables at below. but its query is very slow.
table user
id | username
1 | name1
2 | name2
3 | name3
..
..
table post
id | poster_id | post_content
1 | 2
2 | 3
3 | 10
..
..
table follow
followerid | followtoid
1 | 2
1 | 3
2 | 10
..
..
Assume that all tables have more than 1000 rows.
This's SQL
SELECT *
FROM post
WHERE poster_id IN (
SELECT followtoid
WHERE followerid = $_SESSION['userid']
)
And this's the second cast is very slow too.
I want to list all member by order from their total posts.
SELECT *
FROM user
ORDER BY (
SELECT COUNT(id)
FROM post
WHERE post_id = user.id
) DESC;
Try indexing post.userid, post.poster_id, followtoid.followerid and user.user_id, using CREATE INDEX, and use LEFT JOIN clause on your queries instead:
SELECT *
FROM user u
LEFT JOIN SELECT poster_id, COUNT(*) as count FROM post p GROUP BY poster_id
ON (u.user_id = p.poster_id)
ORDER BY count DESC;
and:
SELECT * FROM post AS p
LEFT JOIN (SELECT followerid FROM followtoid) AS f
ON (p.userid=f.followerid)
WHERE p.userid = {$_SESSION['userid']}
Use a JOIN for the first query
SELECT p.*
FROM post p
JOIN follow f ON p.post_id = f.followtoid
WHERE f.followerid = $_SESSION['userid']
and a JOIN plus a GROUP BY for the second
SELECT u.*, tbl.postCount
FROM user u
JOIN (
SELECT poster_id, COUNT(*) AS postCount
FROM post p
GROUP BY posterID
) tbl ON tbl.poster_id = u.id
ORDER BY postCount DESC
You can accomplish the second query without a subquery:
SELECT u.*, COUNT(p.poster_id) as postCount
FROM user u
LEFT JOIN post p
ON (u.user_id = p.poster_id)
GROUP BY u.user_id
ORDER BY postCount DESC;

WHERE query inside an AND statement? PHP/PDO/MySQL

I have 2 tables on my website, a users table and a user_friendships table each structured as so...
Users
id | user_id | credits_bank | credits_offered
User Friendships
id | user_id | user_followed_id
When my user logs in he is presented with a list of other users on the website - the list of other users are those who are stored in the users table and have a greater value in the credits_bank table than that of the credits_offered table.
When a friendship is created, the session users id is stored in the user_friendships table, and the id of the other member he followed is also stored in the user_friendships table under the column user_followed_id.
The problem is I now need a query to return all users who have move credits_bank than credits_offered and users that aren't already in the user_frienships table in the same record as the session user.
I'm currently using...
SELECT DISTINCT u.*
FROM users u
LEFT JOIN user_friendships uf ON u.user_id = uf.user_followed_id
WHERE u.user_id <> ?
AND u.credits_offered <= credits_bank
AND uf.user_followed_id IS NULL
Update
I want to see a list of users whose credits_bank is a greater value than credits_offered and I only want to show them if they dont already exist in a record in my user_friendships table in the same row as my session user.
Users
id | user_id | credits_bank | credits_offered
___________________________________________________
1 123 10 2
2 231 6 3
3 312 6 5
4 213 2 1
User Friendships
id | user_id | user_followed_id
___________________________________________________
1 123 231
2 123 312
Result
If session user_id = 123 then...
user_id 231 and 312 WOULDN'T show as they are in the user friendships table alongside session user id
user_id 213 WOULD show as they have more credits_bank than credits_offered and arent in friendships table
IF the session user_id was 312 then he would see all results as he isnt friends with anybody in the user_friendships table...
As far as I can tell, you're close. If the user id of the current user is called SESS_USER_ID, something like this should work for you;
SELECT DISTINCT u.*
FROM users u
LEFT JOIN user_friendships uf
ON uf.user_followed_id = u.user_id
AND uf.user_id = SESS_USER_ID
WHERE u.credits_offered <= credits_bank
AND uf.user_followed_id IS NULL
AND u.user_id <> SESS_USER_ID
(note that SESS_USER_ID is used twice in the query to make it simple)
An SQLfiddle to test with.
Try this:
SELECT u.id, u.user_id, u.credits_bank, u.credits_offered
FROM users u
WHERE u.credits_bank>u.credits_offered
AND u.user_id = [ENTER LOGGED IN USERS ID HERE]
AND u.user_id NOT IN (
SELECT f.user_ol
FROM user_friendships f
)
Let me know if you have any issues
EDIT
Latest SQL:
SELECT u.id, u.user_id, u.credits_bank, u.credits_offered
FROM users u
INNER JOIN user_friendships f
ON f.user_followed_id = u.user_id
AND u.credits_bank > u.credits_offered
AND f.user_id != [CURRENT_USER_ID]
AND u.user_id != [CURRENT_USER_ID]

Categories