Using a MySQL query with PHP - php

I am creating a social network in which you can follow someone or be friends with them. The data you are able to see depends on the type of relationship you have with a user. Right now I have two tables to work with. Posts and Relationships.
Posts:
| user_id | post_id | story |
-----------------------------
| 1 | 1 | text. |
-----------------------------
Relationships:
| rel_id | user_1 | user_2| status |
--------------------------------------
| 1 | 1 | 2 | 3 |
--------------------------------------
I also have a users table but I don't think that is important here. SO, basically I want to select all of the posts from users that I am friends with or following. User_2 is always the recipient of the relationship. The numbers 1, 2 and 3 represent the "status" of the relationship. 1 being you are following the recipient, 3 being you are friends, and 4 being you are following the recipient (the only difference is that you also have a pending friend request). I set up a SELECT QUERY but it is not working right.
$query=" SELECT * FROM posts LEFT JOIN relationships ON (posts.user_id=
relationships.user_2 AND relationships.user_1 = $user_id AND relationships.status = 4
OR 3 OR 1)";
It selects all the posts ever, twice. Why is that? I want it to only select the posts where the user posting the post is in a relationship with me, with a status of 1, 3, or 4. What might I be doing wrong? What are other ways to do this?
Thanks in advance!

That's not how OR works. Perhaps you should try IN.
... relationships.status IN (4, 3, 1) ...
As for the duplication, use DISTINCT.

Your OR in the WHERE clause condition is not in the correct syntax. try something like this:
SELECT *
FROM posts a
LEFT JOIN relationships b
ON a.user_id = b.user_2
WHERE b.user_1 = $user_id AND
b.status IN (1,3,4)
I suggest that you use PDO or MYSQLi extensions.
In PDO, it could look like this:
<?php
$stmt = $dbh->prepare("SELECT *
FROM posts a
LEFT JOIN relationships b
ON a.user_id = b.user_2
WHERE b.user_1 = ? AND
b.status IN (1,3,4)");
$stmt->bindParam(1, $user_id);
$stmt->execute();
?>
Remember to always filter your inputs especially it is used querying your database.

Related

Fairly complex SQL statement using inner join (I presume)

I'm having trouble figuring out how to write an SQL query to return results from the following table structure.
The first thing I do is get a list of clients that have a status equal to 1 by:
SELECT * FROM clients WHERE status=1
Then I need to get all user email addresses that belong to a client. My plan was to loop through the results of the query above and running multiple queries for each client. As you can see from the table 'client_user_list' a single user can belong to multiple clients.
I tried doing something like this:
SELECT emailaddress
FROM users
INNER JOIN client_user_list ON users.user_id = client_user_list.user_id
WHERE users.client_id = 1
But it failed. As you can see I'm a total novice when it comes to this stuff. Any help would be appreciated, or feel free to point me to an appropriate resource to learn more. I've looked, but I haven't found anything that covers something complex like this.
Additional info: Using foreign keys there are relationships between clients <-> client_user_list and client_user_list <-> users
clients:
|---------------------------------------|
| client_id | client_name | status |
|---------------------------------------|
| 1 | John Doe | 1 |
| 2 | James Doe | 0 |
|---------------------------------------|
client_user_list:
|----------------------|
| client_id | user_id |
|----------------------|
| 1 | 5 |
| 2 | 6 |
| 1 | 6 |
|----------------------|
users:
|---------------------------------------|
| user_id | emailaddress |
|---------------------------------------|
| 5 | notan#email.com |
| 6 | afake#email.com |
|---------------------------------------|
Thanks so much in advance.
I'm not sure if this is your only problem, since you didn't specify what the exact problem is, but the WHERE-clause of your query contains an error. You query should be changed into this:
SELECT DISTINCT emailaddress
FROM users
INNER JOIN client_user_list ON users.user_id = client_user_list.user_id
WHERE client_user_list.client_id = 1
The users table does not have a field called client_id, the client_user_list table does.
You can get the clients with status = 1 and their users with only one query, by joining all three tables:
select clients.client_id, clients.client_name, users.user_id, users.emailaddress
from clients
inner join client_user_list on client_user_list.client_id = clients.client_id
inner join users on client_user_list.user_id = users.user_id
where clients.status = 1
order by clients.client_id, users.user_id
The following command should resolve this issue
I hope it is userful.
select distinct use.emailaddress
from clients cli
inner join client_user_list cul on (cli.client_id=cul.client_id)
inner join users use on (cul.user_id = use.user_id)
where cli.status = 1

Using a MySQL join

A user can have two types of relationships on my website. Following or Friends. I want to populate each user's news feed with the posts from users they have a relationship with. So far I have this join:
SELECT *
FROM posts a
LEFT JOIN relationships b
ON a.user_id = b.user_2
WHERE b.user_1 = $user_id AND
b.status IN (1,3,4) OR a.user_id = $user_id
ORDER BY a.post_id DESC
b.status is the column from my relationships table that determines the status of the relationship between two users. 1 being following, 3 being friends, 4 being following with a pending friend request. My join works well, except that It it doesn't take into consideration that there is only one row in my 'relationships' table that can represent a friend ship between any two people. There are two rows for following. The first being user 1(mark) following user 2(matt) and user 2(matt) following user 1(mark). But with friendships it is either a row stating one way or the other, with a status of 3. First off, is that smart practice? Or should I have two rows for this type pf relationship as well? Secondly, how can I make my JOIN QUERY also grab posts from users with where there is a relationship between user_1 and user_2 and the status = 3? With no regard to the order user_1 and user_2 are in?
Table Structure:
Posts:
| user_id | post_id | story |
-----------------------------
| 1 | 1 | text. |
-----------------------------
Relationships:
| rel_id | user_1 | user_2| status |
--------------------------------------
| 1 | 1 | 2 | 3 |
--------------------------------------
In your WHERE statement, do something like this so you match either column in the relationship table. The OR gets both of them.
WHERE b.user_1 = $user_id OR b.user_2 = $user_id
Good luck!

Mysql Query from Query results

I am making something like an announcement board that requires readers to acknowledge that they read it, and was wondering if there is a more efficient way of doing this.
I have 3 Tables on MySQL side:
+-----------------+ +-----------------+ +-----------------+
| Announcements | | Acknowledgement | | User |
+-----------------+ +-----------------+ +-----------------+
| announce_id | | ack_id | | user_id |
| announce_msg | | announce_id | | user_name |
| ... | | user_id | | ... |
+-----------------+ +-----------------+ +-----------------+
When a user "reads" the announcement (by clicking a button), Acknowledgment table will be inserted with the Announcement ID and User ID. When a second user "reads" the same announcement, Acknowledgement table will be inserted again with same Announcement ID and the second User ID and so on...
+--------------------------------+
| Acknowledgement |
+--------+-------------+---------+
| ack_id | announce_id | user_id |
+--------+-------------+---------+
| 1 | 1 | 1 |
| 2 | 1 | 4 |
| 3 | 1 | 3 |
| 4 | 3 | 1 |
| 5 | 3 | 6 |
| 6 | 3 | 2 |
+--------+-------------+---------+
Now to the problem. On the front end, when I list all the announcements on a page, I would have to first query for all the announcements. Then, for each announcement, I would have to do another query for all the users that have read this announcement.
$sql = "select * from Announcements";
$result = $pdo->query($sql);
while ($row = $result->fetch())
{
$announce_id = $row['announce_id'];
$announce_msg = $row['annouce_msg'];
$readers = "";
$sql2 = "select u.user_name from Acknowledgement as a INNER JOIN User as u where announcement_id =".$annouce_id;
$result2 = $pdo->query($sql);
while ($row2 = $result2->fetch())
{
$readers .= $row2['user_name'].", ";
}
echo "id:".$annouce_id.", message:".$announce_msg.", Readers:".$readers;
}
So if there 10 announcements on the page, there will be 10 sub-queries for each announcement. What I have now does the job right now... but what if there is 1000 announcements? Then there will be 1000 sub-queries? Sounds like the database will be really hammered. So I'm hoping there is a better way of doing this.
Also, if 1000 people in the user table reads all 1000 announcements, the acknowledgement table will have 1000x1000 entries. seems like the acknowledgement table will become really really long. Will that be a problem as time goes by?
This is a really rough example of what I'm trying to do but it did take me a long time to write all this. If more details is needed let me know.
There is a better way. You can use a single query with group_concat:
select a.*, group_concat(u.user_name separator ', ') as AllUsers
from Announcements a join
Acknowledgement ak
on a.Announce_Id = ak.Announce_Id join
User u
on u.user_ID = ak.User_ID
group by a.announce_id
This uses the MySQL feature of hidden columns to group by only one column (announce_id) but still pull in a bunch of other columns with no aggregations (everything else pulled in by the "*").
If your purpose here is to filter out the announcements that your current user has read, you can do this an entirely different way. Instead of querying for every announcement, and then finding out all the users that have read those announcements and examining those results to find ones that your use has read and trimming them from the displayed list, you can just query in one go for everything a particular user (or list of users) have not yet read.
Change your query to this:
SELECT * FROM Announcements WHERE Announce_id NOT IN (SELECT ANNOUNCE_ID FROM Acknowledgement WHERE User_ID = <INSERT USER ID HERE>)
That should return all Announcement rows that this particular user has not yet acknowledged. If you change that final WHERE clause to be WHERE User_ID IN () then you can specify a list of user IDs.
EDIT: Given the comment you posted above, you could use this query to get all announcements that have been read by no one:
SELECT * FROM Announcements WHERE Announce_id NOT IN (SELECT ANNOUNCE_ID FROM Acknowledgement WHERE User_ID IN (SELECT User_ID FROM User))
The logic for putting together a query to find announcements that haven't been read by someone (if not everyone) is escaping me right this second.
EDIT THE SECOND: Every announcement, and everyone who has and has not read it, requires use of a different kind of join that you've used above, a FULL OUTER JOIN. Unfortunately MySQL doesn't have that feature IIRC, but it can be simulated with a union query
SELECT A.*, ACK.*, U.* FROM Announcements AS A
INNER JOIN Acknowledgement AS ACK ON A.Announce_ID = ACK.Announce_ID
LEFT OUTER JOIN User AS U ON ACK.User_ID = U.User_ID
WHERE U.User_ID IS NOT NULL
UNION ALL
SELECT A.*, ACK.*, U.* FROM Announcements AS A
LEFT OUTER JOIN Acknowledgement AS ACK ON A.Announce_ID = ACK.Announce_ID
RIGHT OUTER JOIN User AS U ON ACK.User_ID = U.User_ID
I think that should do it. No facilities to test at the moment, of course.

mySQL JOIN query beat down

Alright, I'm not the best with JOIN's and after all these years of working with mySQL you think I would be by now at the least minimally decent. Guess I've never really worked on anything superbly complex til now worth needing to join a table. So here I am, confused ever so slightly in need of a helpful example to get me on a roll, something that's pertinent to my actual data that I can make heads or tales of cause all the reading I'm doing online else where just gives me headaches for the moment. I think I might be stuck on the mythology of JOIN's being a hard thing to do, they don't seem like it but when ever I've tried I fail. So anyway I am working with PHP as my server side coding, and I believe MySQL 5.
So heres the construct to an extent.
I have table information and table connections.
Connections has: member_id, connection_id, active
Information has: firstname, lastname, gender, member_id
I should say the tables contain more data per table, but as I understand it I need write a query that I can use the member_id as the connector/foreign key. Where I can use both sides of the information. I need to know if active is 1, and then I need to know all of the columns above mentioned for information.
I tried
SELECT member_id,
connection_id,
active,
firstname,
lastname,
gender,
member_id
FROM connections, information
WHERE connection.member_id = information.member_id AND
connection.active = 1
and I've tried
SELECT * FROM connections, information
WHERE connection.member_id = information.member_id AND
connection.active = 1
With the first one I get member_id is ambitious which is understandable to a point i think cause of the matching columns between the two tables. Then the second query doesn't server me well as it only results with one person.
My Ultimate goal is to find all the connections for a specific member_id in the connections table, while gathering all the information about those connections from the information table using the connection_id as its the same thing as the member_id in the in the information table.
So in laymans terms if I am not making sense lets say I wanted to list out all my friends in from the DB. My connection table lets me know which people I am connected to where member_id is my id and connection_id is my friends member_id on another table. Hopefully that makes more sense. And this is where I am having trouble with my query and trying to write it correctly. If I could get a working sane sample of that I think I might be able to make better sense of JOIN's doesnt help that I also can't figure out what type of JOIN is best suited for my needs either I suppose.
EDIT....
Ok as per request from comment below. Sample data expected output from tables that look similar to this:
Connections Table
member_id, connection_id, active
1 | 2 | 1
1 | 3 | 1
1 | 4 | 1
1 | 5 | 1
2 | 1 | 1
2 | 5 | 1
3 | 1 | 1
Information Table
member_id, firstname, lastname, gender, ...other unimportant rows for this query
1 | Chris | Something | m | ....
2 | Tony | Something | m | ....
3 | Brandon | Something | m | ....
4 | Cassie | Something | f | ....
5 | Jeff | Something | m | ....
6 | John | Something | m | ....
now from the connections table I need to gather all the connection_id's associated with my member_id where active is 1 then from the information table gather everyone firstname, lastname, gender.. Now I know I can do this 2 step where I pool all the connection_id's from connections then run them through a loop of some sort and one by one get the resulting id's from the first query but to me that seems a bit obscure and process intensive which I want to avoid, which brings me here.. Currently from my original query posted to the many shared thus far trying to help my results are to the effect of
1 | Chris | Something | m | 2
1 | Chris | Something | m | 3
1 | Chris | Something | m | 4
1 | Chris | Something | m | 5
what I'd like to see returned is something like
2 | Tony | Something | m
3 | Brandon | Something | m
4 | Cassie | Something | f
5 | Jeff | Something | m
After looking at this I suppose I would also need to know the friendID column that matches my member_id as well but thats something to figure out after this initial hurdle
The error is in your WHERE Clause because instead of Connections you wrote it Connection which then the server generates the error.
...
WHERE connection.member_id = information.member_id AND
connection.active = 1
try this:
SELECT a.Member_ID,
a.FirstName,
a.LastName, a.gender,
b.Connection_ID
FROM Information a INNER JOIN Connections b
on a.Member_ID = b.Member_ID
WHERE b.`Active` = 1
UPDATE
if that's the case then you will most likely have a SELF JOIN
SELECT DISTINCT b.Connection_ID,
c.*
FROM Information a INNER JOIN Connections b ON
a.Member_ID = b.Member_ID
INNER JOIN Information c ON
b.Connection_ID = c.Member_ID
WHERE b.`Active` = 1
AND a.Member_ID = 'ID HERE' -- If you want to get for specific member
The error in the first is "ambiguous" not ambitious. Ambiguous means that the SQL engine doesn't know which column you are talking about, because you have two columns with the same name (different tables but still).
You can fix that by specifying the table name along with the column name where you list the columns for select.
For example
SELECT connections.member_id, connection_id, active, firstname, lastname, gender, information.member_id FROM connections, information WHERE connections.member_id = information.member_id AND connections.active = 1
The problem with returning only one suggests that there is only one record that matches your query but it's hard to guess.
Try changing to:
SELECT * FROM connections c JOIN information i ON i.member_id = c.member_id WHERE c.active = 1
Try this:
SELECT *
FROM information
LEFT OUTER JOIN connections
ON information.member_id = connections.member_id
WHERE connections.active = 1;
You're joining on the wrong tables. You said:
where member_id is my id and connection_id is my friends member_id on another table
Then, what you have to match is connections.connection_id with information.member_id. The simplest solution is:
select c.member_id, c.connection_id, c.active from connections c
join information i on c.connection_id = i.member_id
where c.active = 1 and c.member_id = #yourId
That's all :)

Nested or Joins query for MySQL using PHP

I have many a times tried using nested query for MySQL in PHP, but it does not work. Is it not possible to do nested/Joins queries?
Just a Scenario:
I have two tables one table with user id and the other with data. User logins and with sessions I have to cross check two different tables with user id (user and data). Is it not possible to nest/join these two tables to write a single query statement.
In short is nesting or joining two or more tables permitted in PHP coding?
YES, it is possible to join two or more tables in MySQL (and therefore, also when using PHP).
You need to post your table schema, if you want us to show a relevant join query. You could, however, try something like:
SELECT * FROM user AS t1
CROSS JOIN data AS t2
ON t1.userid=t2.userid
WHERE t1.userid='154'
(This query presumes that there always will be one row with the userid in both tables. You should use LEFT JOIN instead of CROSS JOIN to return a row even if there is no row in data for the userid. 154 is just an example userid.)
Have a look at http://dev.mysql.com/doc/refman/5.5/en/join.html for information on the JOIN syntax.
users
| user_id | username | password | enabled |
|---------|----------|----------|---------|
| 1 | john | sgsd2gg | 1 |
| 2 | jane | sdshdhd | 0 |
users_data
|udata_id| user_id | some_column |
|--------|---------|-------------------|
| 1 | 1 | Some title |
| 2 | 2 | another title |
Since you haven't posted your table schema, I can't give you an exact solution. But supposing you have a users table and a users_data table, where users_data are owned by a user. You can do a join on the table to retrieve all the data.
SELECT * -- Don't select all fields unless you need it
FROM users U LEFT JOIN users_data UD ON U.user_id = UD.user_id
WHERE U.user_id = 1
This would pull all the records for user with an ID of 1. This is a very simplistic join, but it should give you an idea.
Here's an example that visually describes the different options you can use : SQL Join Differences

Categories