Left/Inner join with AND,WHERE, and OR - php

I have 2 tables:
Friends
ID | Profile | Check
------+-----------+---------
int | int | bool
Where ID is person who sent original friend request, Profile is ID of person request was sent to, and Check is 0 = request pending; 1 = request accepted.
Messages
OwnerID | ...
-----------+-------
int | ...
Where OwnerID is ID of member who wrote the message.
So basically, what I am looking at is first:
select all rows from friends_list table where ID or Profile is equal to the memberID cookie. BUT heres my plight: If I send another user a friend request, then my ID is placed in the ID field and their ID is placed in the Profile field of the friend_list table. But if another user requests a friend request from me, then my ID would go into the Profile field and theirs would go in the ID field.
So, I would have a row where ID = 1, and Profile = 2. And the next row would be ID = 3 and Profile = 1. Now, both users with IDs 2 and 3 are friends of mine (ID 1), So I need to show all messages from 1, 2, and 3 (mine and my two friends) where check = 1

I think what you want is this:
(
SELECT m.*
FROM Messages m
INNER JOIN Friends f ON m.OwnerID = f.ID
WHERE f.Profile = ?
) UNION (
SELECT m.*
FROM Messages m
INNER JOIN Friends f ON m.OwnerID = f.Profile
WHERE f.ID = ?
)
You need to look at this a two separate queries, I don't think you can sensibly do this with just a combination of JOINs.
Assuming you are using MySQL, this should not return duplicate rows, because the default modifier for UNION is DISTINCT. Other RDBMS engines may require you to explicitly state this or use some other work-around (for example a GROUP BY on the actual message ID).
You may also want to add an m.Check = 1 condition to the WHERE clause of both queries, to ensure you only get messages where the friend request has been accepted.
Obviously the above is designed to be used as a prepared statement, where both placeholders would be substituted with the same data - the memberID cookie.

Related

Getting data from multiple mysql tables WHERE.

I have 2 database tables.
One called files. Which looks like this.
FILES
USERID FILENAME DEFAULT NETWORKID
88 hello 1 10293
9 bob
43 opener 1 10293
43 facepa
9 closer
Second table user networks
USERID NETWORKID
9 10293
43
My current sql query is
SELECT file,filename,filetype,size, forename, files.userID
FROM (`files`)
LEFT JOIN users ON users.userID = files.userID
WHERE files.userID = $userID ORDER BY id DESC
This currently gets the list of files where userid is 9.
As you can see my userid 9 is also in the usernetworks table and I am connected with network id 10293.
I want to also include in the query, any of the rows that default is 1 and the network id matches to any of those in the usernetworks table with my userID.
So where userid is connected to networkid, also show those results aswell as the ones with userid and no network id.
Any help appreciated.
If I read your logic correctly, then we can implement it by first left joining files to users on the condition that the user matches to your user ID. Then, we can left join again to users, this time on the condition that the file record is default, the network IDs match, and the matching user is also your user.
SELECT f.*
FROM files f
LEFT JOIN users u1
ON f.userID = u1.userID AND f.userID = $userID
LEFT JOIN usernetworks u2
ON f.default = 1 AND
f.networkid = u2.networkid AND u2.userID = $userID
WHERE
u1.userID IS NOT NULL OR u2.userID IS NOT NULL;
Actually, if you don't plan on selecting any columns from the users table then you can probably omit the join to that table completely. I have left it in as it is true to the original query in your question.
I understand you want your files plus the default files in your networks:
SELECT userid, filename, networkid
FROM files
WHERE (userid = $userid
OR (default = 1 AND networkid in (
select networkid from network_users where userid = $userid)))
AND filename like :name
Your SQL mentions fields that are not in your schema description.
If you want to get the data on the basis of network id than please use this query
SELECT file,filename,filetype,size, forename, files.userID
FROM files a, network b
WHERE a.networkID = b.networkID ORDER BY id DESC
.
Hope this will solve your problem

How to check if a user follows another user from a list of users?

I'm creating a follow system in PHP where users can follow/unfollow other users. So far, when a user follows any other user, the id of both the users are stored in 'follow' table in MYSQL database,
u_id | f_id
===========
1 | 2
1 | 3
1 | 5
Where u_id follows f_id
Now when u_id 1 performs a search on the website, all the users with matching search query are presented, each having a button so that u_id 1 may follow them, but there may be some users that are already followed by u_id 1. How do I implement such that those users already followed by u_id 1 does not have that follow button?
One way is to check every result if they are followed by u_id 1 before presenting the search result, but I guess this will be very slow.
Is there any way so that I can do this in a single MYSQL query?
when u_id = 1 performs a search on the website, all the users with matching search query are presented
Looks like you have some kind of query returning user_id and a suggested user f_id to follow. Let assume that is a table suggestion
SELECT s.f_id,
CASE
WHEN f.id IS NULL THEN 'ON'
ELSE 'OFF'
END as ButtonStatus
FROM [suggestion] s
LEFT JOIN [follow] f
ON s.user_id = f.u_id
AND s.f_id = f.f_id
WHERE
s.user_id = #user_id // Variable from your UI.
$sql = "SELECT u.*, f.followingUsersId AS followingUsersId
FROM users AS u LEFT JOIN (SELECT followingUsersId FROM follow WHERE followerUsersId = '".$_SESSION['userid']."') AS f ON u.usersId = f.followingUsersId
WHERE u.usersName LIKE '%$searchvalue%' ORDER BY f.followingUsersId DESC, u.usersId DESC;";
Worked for me!!

Select newest entry from two tables in addition to left join and union mysql query

I have three tables that record conversation activity and one table containing user info
I am trying to put a query together that summarises a users conversations (like an inbox with the last comment visible)
my tables are set up like the below
users
---
company | contact_person | pic_small
alerts
---
comment_id | user_id | poster_id | timestamp
activity
---
comment_id | user_id | comment | timestamp
comments
---
comment_id | user_id | comment | timestamp
When a user initially makes contact, the timestamp, comment_id and id's of the users (person sending and person receiving) get inserted into the alerts table. The user_id, comment_id, timestamp and actual comment also get inserted into the activity table.
Then once the conversation has started, all comments (comment_id, user_id,comment, timestamp) get inserted into the comments table.
As mentioned above, what I am trying to do is summarise a users activity so it looks like their inbox.
I have come up with the below query that gives me the user id's, comment id's and user details of all the conversation activity received or sent by logged in user.
SELECT alerts.comment_id,
alerts.user_id,
alerts.poster_id,
alerts.timestamp,
users.contact_person,
users.company,
users.pic_small
FROM alerts
LEFT JOIN users ON users.user_id = alerts.user_id
WHERE alerts.user_id = %s
GROUP BY alerts.comment_id
UNION
SELECT alerts.comment_id,
alerts.user_id,
alerts.poster_id,
alerts.timestamp,
users.contact_person,
users.company,
users.pic_small
FROM alerts
LEFT JOIN users ON users.user_id = alerts.poster_id
WHERE alerts.user_id = %s
GROUP BY alerts.comment_id
ORDER BY TIMESTAMP DESC
The part I am stuck on is getting the last comment (comment with newest timestamp) from either the activity or comments table (It could be either). Happy to change the above query completely if needed.
Below is what I am trying to achieve, I only want to see the user details of people that have contacted me or who I have contacted - not my own details in my inbox (I can do this with php if needed) - It doesn't matter if the last comment was mine however.
Still it is not clear to me why you are using union.
You can get latest comment by below query, if you want to join some other results of other user_id then you can union these results in same way or let me know if you need different results.
SELECT
comment_id,comment, user_id,poster_id,TIMESTAMP, contact_person,company,pic_small
FROM
(SELECT
alerts.comment_id,alerts.user_id,alerts.poster_id,alerts.timestamp,users.contact_person,users.company,users.pic_small,act.comment
FROM alerts
JOIN activity act
ON act.comment_id=alerts.comment_id
LEFT JOIN users ON users.user_id = alerts.user_id
WHERE alerts.user_id = %s
ORDER BY act.timestamp DESC) a
GROUP BY comment_id;

Check If Some User ID's Are Friends With The Logged In User In A Single Query

I have a simple friends system on my site. Now I'm trying to create a multi-user group messaging system but only between friends. The "To" values of my messaging system are comma values, I want to check if they all are friend with the person sending the message.
For example, I can get all of a user's friends by the following query:
SELECT relation_setter user_id
FROM users_relationships
WHERE relation_getter = {$logged_in_user}
AND active = 1
UNION
SELECT relation_getter user_id
FROM users_relationships
WHERE relation_setter = {$logged_in_user}
AND active = 1
and I have natasha, reeta as a $_POST['to'] value from my message form which I then convert to user ids and get something like 126152, 112238
Now how do I check if these ids are both friends with the logged in user, in a single query. I don't want to run my is_friend function in a loop, which check if a single userid is friends with the logged in user.
Relationships Schema:
users_relationships
id PK
relation_setter FK user_id
relation_getter FK user_id
active smallint(1)
The relation_setter is the one who sent the friend request. To get all my friends I get all the IDs where my ID is either the relation_setter or relation_getter.
users
user_id PK
name
username
password
etc etc...
Your post offers vague insight into the schema, so I will use some assumptions
You can find all of the ids that match their friends via an IN statement. Since you already have them as numeric values with comma's you could do:
SELECT user_id
FROM users_relationships
WHERE relation_getter IN (126152,112238,123456)
AND active = 1
This will return ONLY the records of friends that match. You then could match the number of rows with the number of elements in the query to determine if they're friends or not. You could also just send to the ones that matched.
EDIT
SELECT user_id
FROM users_relationships
WHERE relation_getter IN (126152,112238,123456)
OR relation_setter IN (126152,112238,123456)
AND active = 1
This will return all user ID's of the person's friends be they the getter or setter and it's active.
EDIT 2
new table
relationships_members
id FK (from users_relationships; not unique)
user_id
Sample of relationships_members would be
id | user_id | relation_setter
--------------------------------------
1 12345 1
--------------------------------------
1 98765 0
--------------------------------------
Then if you queried, you would only receive users_relationships ID that were valid
select distinct a.id, b.user_id as friend
from (
select distinct id as friend
from relationships_members
where user_id = {$logged_in_user}
) a, relationships_members b
WHERE a.id = b.id
and user_id IN (126152,112238,123456)

Simplifing a mysql query

Scenario
I have three elements in this problem. One is an array of ids in this format: (1,3,5,6,8). That array is a list of id of users I want to display. The second element is table that contains user information something simple like: id name surname email. The third element is a second table that contains users configuration. There are two parameters in that last table, one is lid, and the other is usraction (among others, but the important are those two). lid represent a permission type and usraction the value, if the user wants his data to be public there will be a row on that table where lid=3 and usraction="accepted", also I register the datetime of the action every time the user changes this permission, so each time he change it a new row is added, and in order to retrieve the actual state of the permission i have to retrieve the last row for the user an check the value of usraction like this:
SELECT * FROM legallog WHERE uid = '.$user['id'].' AND lid = 3 ORDER BY ABS(`registration` - NOW()) LIMIT 1
Then in php:
if($queryresult && $queryresult[0]['usraction']=='accepted') //display data
The problem
In the scenario id described how im getting the actual state of the permission set by one user at the time, the problem now is I want to sort of clean an array of ids in one or two sql calls. Lets say I want to print the user information of 4 users, one function gives me the ids in this format: (2,6,8,1), but those users may not want to display their information, using the query I showed before I can make a call to the sql server for each user and then generate a new array, if the users who authorize are 1 and 8 the result array will be (8,1).
The think is whit an array of 100 users I will make 100 calls, and I dont want this, is there a way to solve this in one or two querys?
A query such as this gets you the information you want:
select u.*,
(select usraction from configuration c where c.userid = u.userid and c.lid = 3 order by datetime limit 1
) as lastLid3Action
from users u
where u.userid in (1,3,5,6,8)
If you only want "accepted" values, then make this a subquery:
select t.*
from (select u.*,
(select usraction from configuration c where c.userid = u.userid and c.lid = 3 order by datetime limit 1
) as lastLid3Action
from users u
where u.userid in (1,3,5,6,8)
) t
where LastLid3Action = 'Accepted'
As I understand you have two tables in the first table, where the user information is stored; and the second table, where the user permission is stored. And you want to get information from the first table using permission from the second table, then you need this query:
SELECT a.*
FROM first-table-name AS a
RIGHT JOIN second-table-name AS b a.uid = b.lid
WHERE uid in (1,3,5,6,8) AND usraction='accepted'
ORDER BY ABS)
LIMIT 1
You question is somewhat vague, but if you are asking how to select a number of records when you have a list of ids, the answer is:
select column, list, goes, here from tablename
where id in (1,5,8,12,413);
That will get you the values of the columns you list for just the records that match your array of ids.

Categories