I have a usermessages table in which all messages sent between two users on a site are stored.
Each message has a sourceUserId and a friendId, these are the sender and receiver.
Every user message inbox lists all sent and received messages and each message shows which user has sent or received that message.
The problem
As we are listing sending and receiving users, some columns are the wrong way around, for example if the userId of the current user is 1
sent messages will have a sourceUserId of 1
received messages will have a friendId of 1
If I try and do the whole inbox with one query then I have to currently do two joins on both sourceUserId and friendId as I can't tell which is the currently logged in user.
I already know the username of the currently logged in user so it does not seem right to have two joins when only one is needed?
I am wondering if it is possible to use some sort of case in a mysql query to effectively achieve the following and reduce the amount of data that has to be looked up each time ..
SELECT um.message, UNIX_TIMESTAMP(um.time), um.read, user.username
FROM usermessages um
CASE
WHEN um.friendId = 1
INNER JOIN user ON um.sourceUserId = user.id
WHEN um.sourceUserId = 1
INNER JOIN user ON um.friendId = user.id
END
WHERE (um.friendId = 1 OR um.sourceUserId = 1)
You need to use CASE for ON clause instead
SELECT um.message, UNIX_TIMESTAMP(um.time), um.read, user.username
FROM usermessages um
INNER JOIN user ON
CASE
WHEN um.friendId = 1 THEN um.sourceUserId
ELSE um.friendId
END = user.id
WHERE (um.friendId = 1 OR um.sourceUserId = 1)
(or move the comparison = user.id inside CASE if you like it better)
Another approach, instead of using case when, do it the boolean way:
SELECT um.message, UNIX_TIMESTAMP(um.time), um.read, user.username
FROM usermessages um
INNER JOIN user ON
(um.friendId = 1 AND um.sourceUserId = user.id)
OR
um.friendId = user.id
WHERE (um.friendId = 1 OR um.sourceUserId = 1)
Related
I have two tables.
One table has everything I need including a cardId(PK)
The other name is a user type table. This table stores the userId and the cardId(FK).
SELECT ci.cardId, ci.year, ci.name, ci.number
FROM USERCARDS uc
INNER JOIN CARDINDEX ci ON uc.cardId = ci.cardId
WHERE uc.userId = 'USER_ID'
So for this query, it will display the cardId, year, name, and number from the CARDINDEX. It will only display the cards that the user has saved in USERCARDS.
I want to do the opposite. If a user is looking at, lets just say, 5 cards, but the CARDINDEX has 50 cards, this query will display the information for the five cards. However, for a new query, I would want to show the remaining 45 cards. Basically, they cant add a card they already are following.
I tried to have uc.cardId != ci.cardId but that didn't work. Im kind of lost.
You can phrase this as a LEFT JOIN:
SELECT ci.cardId, ci.year, ci.name, ci.number
FROM CARDINDEX ci LEFT JOIN
USERCARDS uc
ON uc.cardId = ci.cardId AND
uc.userId = 'USER_ID'
WHERE uc.cardID IS NULL;
Alternatively, you could write this using `NOT EXISTS:
SELECT ci.cardId, ci.year, ci.name, ci.number
FROM CARDINDEX ci
WHERE NOT EXISTS (SELECT 1
FROM USERCARDS uc
WHERE uc.cardId = ci.cardId AND
uc.userId = 'USER_ID'
);
I have two tables, one for registered users and one to store votes.
We are logging in with registrants.id and registrants.zipcode. Once they vote their votes are inserted into the votes table, along with their Registration ID.
Im trying to right a select statement that returns a record that will select all the records for Matched ID and Zipcode, but the ID is not in the Votes.voter column. i have tried all kinds of variations of all the joins i can think of. is it something simple i am missing.
SELECT * FROM registrants
LEFT JOIN votes on registrants.id = votes.voter
WHERE registrants.id = 1 AND registrants.zipcode = 46706 and votes.voter <> 1
Perhaps a not exists query:
select * from registrants
where registrants.zipcode = '46706'
and not exists (select 1 from votes where registrants.id = votes.voter)
I want to show the message list like facebook messenger where in left corner you can see all the message you make.
user_table
user_id
user_firstname
user_latsname
message_table
message_id
message_user_id
message_to_user_id
message_content
message_time_stamp
My SQL
SELECT user_table.user_id,
CONCAT(user_table.user_firstname,' ',user_table.user_lastname) AS user_fullname,
message_table.message_user_id,
message_table.message_content,
message_table.message_time_stamp
FROM user_table
INNER JOIN message_table
ON user_table.user_id = message_table.message_user_id
WHERE (message_table.message_to_user_id = '$session')
ORDER BY message_table.message_time_stamp DESC
My code works fine if someone message me first.
It show in my message list that someone message me.
But when i'm the one who make the first message.
It doesn't show in my message list.
He should reply in my message before i can see it in my message list.
But i want to show when someone message me and when i'm the one who make the first message.
message_table with sample data
user_table with sample data
result
But when i add new user in the user_table and message him. it will not show in my Message List.
I want my expected result is when i message new user it will show in my message list
your line (in sql query)
message_table.message_to_user_id = '$session'
is probably the reason, why you don't see the messages you send yourself (since you are not the recipient)
to fetch all messages you're involved in, it should probably be:
message_table.message_to_user_id = '$session' or message_table.message_user_id = '$session'
I hope $session is not user-provided, or you've got some possible sql-injection at hand ;o)
SOLUTION
SELECT user_id, user_fullname, message_content
FROM
(
(SELECT user_table.user_id,
CONCAT(user_table.user_firstname,' ',user_table.user_lastname) AS user_fullname,
message_table.message_user_id,
message_table.message_content,
message_table.message_time_stamp
FROM user_table
INNER JOIN message_table
ON user_table.user_id = message_table.message_to_user_id
WHERE (message_table.message_user_id = '$session')
)ORDER BY message_time_stamp DESC
UNION DISTINCT
(SELECT user_table.user_id,
CONCAT(user_table.user_firstname,' ',user_table.user_lastname) AS user_fullname,
message_table.message_user_id,
message_table.message_content,
message_table.message_time_stamp
FROM user_table
INNER JOIN message_table
ON user_table.user_id = message_table.message_user_id
WHERE (message_table.message_to_user_id = '$session')
)ORDER BY message_time_stamp DESC
) as id GROUP BY user_id ORDER BY message_time_stamp DESC
Here's the solution what i made in my problem. I made 2 select statement where the first select only select where i'm the one who makes the first message and the second select statements select where someone first message me. And then i Union it.
I'm new to MySQL and I'm having problem with JOIN. Please give me some hint on how to achieve what I need.
My Table:
"user" table:
- user_id
- user_name
- user_email
"favouriteRestaurant" table:
- favrst_id
- user_id
- rst_id
"restaurant" table:
- rst_id
- rst_name
- rst_city
- rst_cuisine
- rst_phone
- rst_latitude
- rst_longitude
My query process:
Get user_id "WHERE" user_email match provided email address.
Use the user_id to query "favouriteRestaurant", if data available.
Get rst_name of matching rst_id from "favouriteRestaurant" table.
The final data I need is:
favrst_id
rst_id
rst_name
rst_city
rst_cuisine
rst_phone
rst_latitude
rst_longitude
I hope my explanation is clear enough. If it's not clear please ask/comment. Thank you very much.
The following is the actual SQL (above table are simplified) I've tried so far but the result is definitely not what I wanted. It give me all restaurant instead of matching in favRst.
SELECT
user.email,
user.user_id,
favourite_rst.restaurant_id,
favourite_rst.restaurant_id,
favourite_rst.user_id,
restaurant.name
FROM
user,
favourite_rst,
restaurant
WHERE
(user.email = 'user#abc.com')
You can also try this:
SELECT FR.favrst_id, FR.rst_id, R.rst_name, R.rst_city,
R.rst_cuisine, R.rst_phone, R.rst_latitude, R.rst_longitude
FROM user U,
favouriteRestaurant FR,
restaurant R
WHERE U.user_email = "aaaa#example.com"
and U.user_id = FR.user_id
and FR.rst_id = R.rst_id
and compare the execution time using inner join and without using inner join.
Try with this :
SELECT favrst_id, FR.rst_id, rst_name, rst_city,
rst_cuisine, rst_phone, rst_latitude, rst_longitude
FROM user U
INNER JOIN favouriteRestaurant FR ON U.user_id = FR.user_id
INNER JOIN restaurant R ON FR.rst_id = R.rst_id
WHERE user_email = "%$email%"
Hope it helps you
SELECT r.* , fr.favrst_id FROM restaurant r LEFT JOIN favourite_rst fr ON r.rst_id = fr.rst_id LEFT JOIN user u ON fr.user_id = u.user_id WHERE u.user_email = "abc#example.com"
I have a crossreference table owner_meeting_crossref with a column (owner_id) for owner IDs and column (meeting_id) for meeting IDs that the owner has access to.
My php script is sent an array of meetings, and I know the current user ID is $current_user_id. How can I efficiently check that the user (owner) has access to the meeting IDs sent in?
One option would be to fetch the meetings from the list that the user has access to, then calculate the difference.
$meetingStr = implode(',', array_map('intval', $meetings));
$accessibleMeetingQuery = $db->prepare("
SELECT meeting_id
FROM owner_meeting_crossref
WHERE owner_id=:uid AND meeting_id IN ($meetingStr)
");
$accessibleMeetingQuery->execute(array(':uid' => $current_user_id));
$accessibleMeetings= $accessibleMeetingQuery->fetchAll(PDO::FETCH_COLUMN);
$inaccessibleMeetings = array_diff($meetings, $accessibleMeetings);
Another would be to do it all from SQL
SELECT m.id
FROM meetings AS m
LEFT JOIN owner_meeting_crossref AS om
ON m.id=om.meeting_id AND om.owner_id=:uid
WHERE m.id IN ($meetingStr)
AND om.meeting_id IS NULL