mysql: linking 2 tables with 2 different fields - php

I have a user table, e.g.
userId
userName
and I have a message table, e.g.
messageId
messageToId
messageFromId
messageContent
I am trying to make a query to pull a message, but also get the user names from the user table based on the messageToId and messageFromId.
I have done this before with only 1 field between tables, e.g.
SELECT message.*, user.userName
FROM message, user
WHERE user.userId = message.messageToId
AND messageId = (whatever)
But I am having trouble with 2 links.
I want the result as follows:
messageId
messageToId
toUserName
messageFromId
fromUserName
messageContent
Any help would be much appreciated, or if someone had another way of attempting a private message system with PHP/MySQL.

You just have to use joins and different table aliases:
SELECT m.*, u1.userName AS toUserName, u2.username AS fromUserName
FROM message m INNER JOIN user u1 ON m.messageToId = u1.userId
INNER JOIN user u2 ON m.messageFromId = u2.userId
WHERE messageId = "XXX";

You need to use a join from to achieve this:
SELECT `m`.*,
`to`.`userName` AS `to`,
`from`.`userName` AS `from`,
FROM `message` `m`
JOIN `user` `to` ON `m`.`messageToId` = `to`.`userId`
JOIN `user` `from` ON `m`.`messageFromId` = `from`.`userId`
WHERE `m`.`messageId` = 1
So you join against the user table twice to get both users for a particular message. To do this you need to use table aliases as I have done with to and from so that you distinguish between them.
I have also used a field alias to get their usernames separately eg:
`to`.`username` AS `from`

Will this work?
SELECT b.userName AS author, c.userName AS reciever, a.messageId, a.messageContent FROM message a JOIN user b ON a.messageFromId = b.userId JOIN user c ON a.messageToId = c.userId

Related

What Sql Join can I use to combine my three tables

I made a query that user can see all the post of active users but not of those inactive, but also they should not see the post of users they blocked or blocked them how can I do that?, the block_users table has block_by_userid and blocked_userid column.
I tried INNER JOIN the post table with members table which every inactive users post cannot be seen anymore., How will I combine the block_users table?
$GetPost = "SELECT Post.* FROM Post
INNER JOIN Members ON Post.Poster_user_id = Members.User_id
WHERE Status='active'";
you might try FULL OUTER JOIN
the idea it to get all items in both tables member and block_users and then filter the data using where clause, i am sorry if i miss using the fields name , so please check the tables names, i assume block_users.block_by_userid contained the blocked user id if not use the correct field
$GetPost = "SELECT Post.* FROM Post
INNER JOIN Members ON Post.Poster_user_id = Members.User_id
FULL OUTER JOIN block_users ON Members.User_id = block_users.user_id
WHERE Status='active'
AND
WHERE block_users.block_by_userid != Members.User_id";
Suppose I am doing this for a user xyz whose user_id is 123 then below is a query which will return expected output for user 123.
Query:
SELECT Post.* FROM Post
INNER JOIN Members ON Post.Poster_user_id = Members.User_id
WHERE Status='active' and post.poster_user_id NOT IN(select block_by_userid from block_users where blocked_user_id = 123 UNION select blocked_user_id from block_users where block_by_userid = 123)

Mysql inner join/ multiple selects in one query?

Hi all!
I'm scripting a guestbook (personalized for each user). I have one table for users and a different one for the guestbook. Now, the way I'm currently displaying the name of the author of a post is not optimal. I simply have a row in the DB for "fromname" i.e the authors name.
I would like to select the authors name based on the authors ID and matching that to their name in the "users" table.
So... This is my mysql query right now:
$sql = " SELECT
pid,toid,fromid,message,fromname,name,pdate,flag
FROM gbook INNER JOIN users
ON id='{$_GET['id']}'
WHERE toid='{$_GET['id']}'
ORDER BY pdate DESC";
I guess I need to like... Select the name on a different condition but in the same query. But I don't know how.
I hope you understand my problem.
Help will be greatly appreciated!
/Jafool
Assuming your users table has a column called username, the following should do what you want:
SELECT
pid,
toid,
fromid,
message,
u.username,
name,
pdate,
flag
FROM gbook INNER JOIN users u
ON id='{$_GET['id']}'
WHERE toid='{$_GET['id']}'
ORDER BY pdate DESC"
All I did was alias the user table (as u), and refered to u.username instead of the fromname you had before.
From what I am seeing it looks like you need to link to the users table twice since you have a fromid and a toid. If you have a users table, why would you have a fromname field in the gbook table? Anyway if my assumption is correct then you may be interested in the following query:
SELECT g.*, u1.username AS ToUser, u2.username AS FromUser
FROM gbook AS g
INNER JOIN users AS u1 ON u1.id = g.toid
INNER JOIN users AS u2 ON u2.id = g.fromid
WHERE g.toid = '{$_GET['id']}'
ORDER BY g.pdate DESC
Hard coding the name in the guestbook table is indeed dirty. Assuming your table structure is something like this:
users( id, name )
gbook( pid, toid, fromid, message, fromname, name, pdate, flag )
your query is already almost ok. Just change it as follows to select all columns of both tables:
$sql = " SELECT *
FROM gbook g INNER JOIN users u
ON u.id=g.fromid
WHERE toid='{$_GET['id']}'
ORDER BY pdate DESC";
Then you can display the name with something like
$result = mysql_query($sql);
while( $val = mysql_fetch_array($result) )
{
$username = $val["u.name"];
}

MySQL multiple table SELECT

I have three tables:
Table(attribute1, attribute2...);
---------------------------------
Users(iduser, username)
Link(idlink, title, userid)
Comment(idcomment, content, linkid, userid)
How to select:
Link title, with corresponding username and number of comments?
I'm currently doing like this:
Q1-Select links (SELECT * FROM `links`)
Q2-Extract usernames from previous query(Q1) - (SELECT username FROM `user` WHERE iduser=Q1.userid
Q3-Extract number of comments from Q1 by id (SELECT COUNT(*) as comments FROM `comment` WHERE linkid='Q1.idlink')
I believe we can do this in much more optimized way. I got idea how to get Link with corresponding username but I got stuck when I need to count comments.
SELECT iduser, username, Link.title, COUNT(idcomment)
FROM Users
LEFT JOIN Link ON (iduser = userid)
LEFT JOIN Comment ON (linkid = idlink)
GROUP BY iduser, idlink
Note that your Comment table is somewhat badly designed - the 'userid' field is not necessary, and can actually lead to situation where you've got a cross-linked record. e.g. a Comment belonging to user A might could be linked to a Link record belonging to user B.
It is good practice to get into the habit of putting the fields you want into both the SELECT and GROUP BY clauses, that way it won't come as such a shock when you have to use an RDBMS that insists on it.
SELECT
`l`.`idlink`,
`l`.`title`,
`u`.`username`,
COUNT(`c`,`idcomment`) AS `comment_count`
FROM `links` `l`
INNER JOIN `users` `u`
ON `l`.`userid` = `u`.`iduser`
LEFT JOIN `comments` `c`
ON `l`.`idlink` = `c`.`linkid`
GROUP BY
`l`.`idlink`,
`l`.`title`,
`u`.`username`
SELECT
l.idlink
, l.title
, l.userid
, u.iduser
, u.username
, c.idcomment
, c.content
FROM Link AS l
JOIN Users AS u ON u.iduser=l.userid
JOIN Comment AS c ON c.linkid=l.idlink

contactlist mysql query

Im making a codeigniter webapp where users can add each other in a contactslist.
The table looks like this:
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_1` int(11) NOT NULL,
`user_2` int(11) NOT NULL,
`accepted` tinyint(2) NOT NULL,
PRIMARY KEY (`id`)
The userid for the user that makes the request to add the contact is always stored in user_1 column. The other users userid is stored in user_2. user_2 then has to accept the request and the 'accepted' column gets updated to 1.
I want to list all contacts that are accepted (WHERE accepted = 1) in a html table, and the contact requests (accepted = 0) in another.
My question is: How can i make a mysql query that selects all the rows and just get the userid from the contact? Its a problem since they can be in either user_1 or user_2 (Depending on if they requested or accepted).
Should i change the db table in some way to achieve this. Or could i make a query (active rcords preferably) that accomplish this?
Any help is appreciated
Thanks in advance
George
Update:
So the final query looks like this:
SELECT DISTINCT users.id, users.username, contacts.accepted
FROM users
LEFT JOIN contacts ON users.id = contacts.user_1
WHERE contacts.user_2 = ' . $this->session->userdata('user_id') . '
UNION DISTINCT
SELECT DISTINCT users.id, users.username, contacts.accepted
FROM users
LEFT JOIN contacts ON users.id = contacts.user_2
WHERE user_1 = ' . $this->session->userdata('user_id')
And works exactly as i described :)
Use a UNION query. See the documentation.
SELECT DISTINCT user_1 userid FROM user WHERE accepted = 1
UNION DISTINCT
SELECT DISTINCT user_2 userid FROM user WHERE accepted = 1
About the join, you'd use something like below for each part of the UNION
SELECT DISTINCT users.userid, users.username, contacts.accepted
FROM users
LEFT JOIN contacts ON users.userid = contacts.user_1
WHERE contacts.user_2 = ?
Shouldn't the contactlist be owned by the user?
create table Contactlist (
OwnerID int, -- ID of the owning User
ContactID int, -- ID of the contact User
Accepted bool)
-- With composite primary key on OwnerID, ContactID
This way the query would be
select * from User
left outer join Contactlist on User.ID = Contactlist.OwnerID
left outer join User as Contact on Contactlist.ContactID = Contact.ID
Sorry... Overthunk the select ;)
select * from Contactlist
inner join User on Contactlist.ContactID = User.ID
where Contactlist.OwnerID = <the querying users ID>
(MSSQL syntax)
You can use queries but it will create problems later on I guess as I have also faced this problem before. You can insert new entries in the same table when a user accepts the request and mark the new record as accepted but this time the user_1 becomes user_2 and vice versa.
Alias with joins is waht I think you are asking.
Something like.
Select c.id, uRequest.UserName, uRequested.UserName From Contacts c
inner join Users As uRequest On c.User_1 = uRequest.id
inner join Users As uRequested On c.User_2 = URequested.id
Where accepted = 1
will give you all contacts where the request has been accepted.

Retrieving the latest note (by timestamp) in a single query from a 1:n table

Let's say I have two tables, users and notes. Let's say the schemas look like this:
users
id, name, field2, field3
notes
id, user_id, subject, heading, body, timestamp
What I want to do is select every user, and the LATEST (just 1) note posted by each user based on the timestamp to show in an overview report.
How would I go about doing this? Please note that the DB is MySQL.
Thanks!
select users.name, notes.subject, notes.heading, notes.body
from users, notes
where users.id = notes.user_id
and notes.timestamp = (select max(timestamp) from notes where user_id = users.id)
select u.id, u.name, n.id as note_id, n.subject, n.heading, n.body, n.timestamp
from users u
left outer join (
select user_id, max(timestamp) as timestamp
from notes
group by user_id
) nm
left outer join notes n on nm.user_id = n.user_id and nm.timestamp = n.timestamp
Note that this could potentially return duplicates if the user has two notes with the exact same timestamp. I have assumed this is not the case.
SELECT *
FROM `users`
LEFT JOIN `notes`
ON `user_id` = `users`.`id`
WHERE `notes`.`timestamp` = (
SELECT MAX(`timestamp`)
FROM `notes` AS `notes_1`
WHERE `notes_1`.`user_id` = `notes`.`user_id`
)

Categories