How to use an IN statement to select many user's statuses? - sql

My statuses returns many statuses:
select message from status where uid = me()
Friend's statuses returns many statuses:
select message from status where uid in ("639620453")
Combining both returns a single status:
select message from status where uid in ("36818590","639620453")
It looks like a bug with the platform.
Does anyone know an alternate way to select many users' statuses at once?

There does seem to be a bug with this that you should log here. A workaround might be to query the stream table.
select message, source_id
from stream
where source_id in ("36818590","639620453")

Related

Build a Query to get the informations from a specific user

I'm building a Chat with three Tables.
Conversation, Conversation_reply and user
Conversation Columns
id
user_one
user_two
Conversation_reply Columns
id
user_id
conversation.id
reply
User Columns
id
username
I would like to build a list with the name from the users that are chating with a specific user.
Example, my ID is 711, and I am talking with three persons, I would like to get the username from those three persons.
I'm having some issues building this Query because the user_one and user_two are relative, the ID from the receiver sometimes can be inserted as user_one, or user_two. It depends on which user starts chatting first.
How can I build a Query to do that?
Thanks.
Depending on your RDBMS you can check IF/ELSE, CASE/WHEN syntax.
Based on it you write statement:
SELECT if (user_one=711) user_two ELSE user_one
FROM conversation
where user_one=711 OR user_two=711
This is pseudocode, but idea should be clear.

How to tightly contain an SQL query result

I'm writing an application that implements a message system through a 'memos' table in a database. The table has several fields that look like this:
id, date_sent, subject, senderid, recipients,message, status
When someone sends a new memo, it will be entered into the memos table. A memo can be sent to multiple people at the same time and the recipients userid's will be inserted into the 'recipients' field as comma separated values.
It would seem that an SQL query like this would work to see if a specific userid is included in a memo:
SELECT * FROM memos WHERE recipients LIKE %15%
But I'm not sure this is the right solution. If I use the SQL statement above, won't that return everything that "contains" 15? For example, using the above statement, user 15, 1550, 1564, 2015, would all be included in the result set (and those users might not actually be on the recipient list).
What is the best way to resolve this so that ONLY the user 15 is pulled in if they are in the recipient field instead of everything containing a 15? Am I misunderstanding the LIKE statement?
I think you would be better off having your recipients as a child table of the memos table. So your memo's table has a memo ID which is referenced by the child table as
MemoRecipients
-----
MemoRecipientId INT PRIMARY KEY, IDENTITY,
MemoId INT FK to memos NOT NULL
UserId INT NOT NULL
for querying specific memos from a user you would do something like
SELECT *
FROM MEMOS m
INNER JOIN memoRecipients mr on m.Id = mr.memoId
WHERE userId = 15
No, you aren't misunderstood, that's how LIKE works.. But to achieve what you want, it would be better not to combine the recipients into 1 field. Instead try to create separate table that saves the recipient list for each memo..
For me I will use below schema, for your need:
Table_Memo
id, date_sent, subject, senderid, message, status
Table_Recipient
id_memo FK Table_Memo(id), recipient
By doing so, if you want to get specific recipients from a memo, you can do such query:
SELECT a.* FROM Table_Memo a, Table_Recipient b
WHERE a.id = "memo_id" AND a.id = b.id_memo AND b.recipient LIKE %15%
I am not sure how your application is exactly pulling these messages, but I imagine that better way would be creating a table message_recepient, which will represent many-to-many relationship between recipients and memos
id, memoId, recepientId
Then your application could pull messages like this
SELECT m.*
FROM memos m inner join message_recepient mr on m.id = mr.memoId
WHERE recepientId = 15
This way you will get messages for the specific user. Again, don't know what your status field is for but if this is for new/read/unread, you could add in your where
and m.status = 'new'
Order by date_set desc
This way you could just accumulate messages, those that are new

"subquery returns more than 1 row" error.

I am new to web programming and I'm trying to make a twitter-clone. At this point, I have 3 tables:
users (id, name)
id is the auto-generated id
name of the user
tweets (id, content, user_id)
id is the auto-generated id
content is the text of the tweet
user_id is the id of the user that made the post
followers (id, user_id, following_id)
id is the auto-generated id
user_id is the user who is doing the following
following_id is the user that is being followed
So, being new to sql as well, I am trying to build an SQL statement that would return the tweets that the currently-logged in user and of everyone he follows.
I tried to use this statement, which works sometimes, but other times, I get an error that says "Subquery returns more than 1 row". Here is the statement:
SELECT * FROM tweets
WHERE user_id IN
((SELECT following_id FROM followers
WHERE user_id = 1),1) ORDER BY date DESC
I put 1 as an example here, which would be the id of the currently logged-in user.
I haven't had any luck with this statement; any help would be greatly appreciated! Thank you.
In one comment you ask is it generally better to use a subquery or a union. Unfortunately, there is no simple answer, just some information.
Some varieties of SQL have problems optimising the IN clause if the lsit is large, and may perform better in any of the following ways...
SELECT * FROM tweets
INNER JOIN followers ON tweets.user_id = followers.following_id
WHERE followers.user_id = 1
UNION ALL
SELECT * FROM tweets
WHERE user_id = 1
Or...
SELECT
*
FROM
tweets
INNER JOIN
(SELECT following_id FROM followers WHERE user_id = 1 UNION SELECT 1) AS followers
ON tweets.user_id = followers.following_id
Or...
SELECT
*
FROM
tweets
WHERE
EXISTS (SELECT * FROM followers WHERE following_id = tweets.user_id and user_id = 1)
OR user_id = 1
There are many, many alternatives...
Some varieties of SQL struggle to optimise the OR condition, and end up checking every record in the tweets table instead of utilising an INDEX. This would make the UNION option preferrable, because each half of the query will then benefit from an index on the user_id field.
But you CAN actually refactor this corner case out of your code altogether : Make every user a follower of themselves. This would then mean that getting tweets for followers would naturally include the user themselves. Whether this would make sense in all cases is dependant on your design and other functional requirements.
In short, your best bet is to create some representative data and test the options. But I wouldn't really worry about it for now. As long as you encapsulate this code in one place, you can just pick one that you are most comfortable with. Then, when you have the rest of the system hashed out, and you're much more confident that things won't change, you can go back and optimise if necessary.
SELECT *
FROM tweets
WHERE
user_id IN (SELECT following_id FROM followers WHERE user_id = 1)
OR user_id = 1
ORDER BY date DESC
try this
SELECT * FROM tweets WHERE user_id = [YourUser]
UNION
SELECT * FROM tweets WHERE user_id in (SELECT following_id FROM followers WHERE user_id ? [YourUser]
shall work even if you've got no followers for your user
There's also a solution with joins, but actually I'm in a hurry. Will try to write the query as soon as I have the time to. Some other will probably answer by then. Sorry.

Database design for email-style application

I'm looking for some advice on how to design a database for an email-style application, specifically how to handle sending a message to multiple users, and displaying what messages were sent to what users.
This is what I have so far:
Messages (Primary Key is Id)
Id (Identity)
SenderId (Foreign Key to Users.Id)
<message data>
ReceivedMessages (Primary key is MessageId + RecipientId)
MessageId (Foreign Key to Messages.Id)
RecipientId (Foreign Key to Users.Id)
IsRead
So for every message sent, there would be one row in Messages, with the data, and then one row for each recipient in ReceivedMessages.
But what if I want to view all the messages sent by a user, and who they were sent to? For each message, I'd need to find all the ReceivedMessages rows for that message, and join all of those with the user table, and then somehow concat all the names (something like this: Concatenate many rows into a single text string?). Might this cause scaling issues, or is it not really anything to worry about?
Any thoughts/suggestions? Thanks.
I see no problem with your design, and would not anticipate and scalability issues with proper indexing on your tables (unless you are talking about massive scale, e.g. gmail, Yahoo mail, etc.).
As far as concatenating the recipient names, I would recommend you do this on the application side and not in SQL, or determine whether you need to do it at all (you might want to show a list and not a concatenated string).
all the messages sent by a user, and who they were sent to
You can do it as an aggregate query, something like:
SELECT u1.user_name, m.message, GROUP_CONCAT(DISTINCT u2.user_name)
FROM messages m JOIN users u1 ON (m.senderID=u1.user_id)
JOIN receivedmessages r ON (m.id=r.messageId)
JOIN users u2 ON (r.RecipientId=u2.user_id)
GROUP BY u1.user_name, m.message;
But because Recipients is essentially unlimited, you may run up against the string length limit on GROUP_CONCAT.
So it's likely better to do an unaggregated select and process the records for display in your application layer:
SELECT u1.user_name, m.message, DISTINCT u2.user_name
FROM messages m JOIN users u1 ON (m.senderID=u1.user_id)
JOIN receivedmessages r ON (m.id=r.messageId)
JOIN users u2 ON (r.RecipientId=u2.user_id)
ORDER BY u1.user_name, m.sent_date, u2.user_name;
Users change name and email, but not their login. Consider mimicking what happens in a unix-based mailbox (e.g. pine) instead:
received_messages (
user_id,
message_id,
message_date,
message_title,
message_content,
message_sender,
message_recipient,
message_is_read
)
and sent_messages along the same lines, i.e. two "files" per user.
Or even merging the latter two with a sent/received flag.
I am facing the same challenge of creating an email or messaging system for a website... You guys forget one thing... IsRead, IsDraft, IsFlagged, IsReply, IsTrash, etc... need to be in a separate table since the same message will be flagged, read or unread by two or more people!! So, we must have a Status table as shown below...
StatusID int
MessageID int
MemberID int
DateTime datetime
IPAddress varchar(65)
IsRead char(1)
IsDraft char(1)
IsFlagged char(1)
IsForwarded char(1)
IsReply char(1)
IsTrash char(1)
You will need at least three tables besides the member or user table:
mail
folders
status
attachment
log
If this is for an existing website... I would separate the mail system into a separate database if you expect this mail system to have a lot of activity.

Fetch unread messages, by user

I want to maintain a list of global messages that will be displayed to all users of a web app. I want each user to be able to mark these messages as read individually. I've created 2 tables; messages (id, body) and messages_read (user_id, message_id).
Can you provide an sql statement that selects the unread messages for a single user? Or do you have any suggestions for a better way to handle this?
Thanks!
Well, you could use
SELECT id FROM messages m WHERE m.id NOT IN(
SELECT message_id FROM messages_read WHERE user_id = ?)
Where ? is passed in by your app.
If the table definitions you mentioned are complete, you might want to include a date for each message, so you can order them by date.
Also, this might be a slightly more efficient way to do the select:
SELECT id, message
FROM messages
LEFT JOIN messages_read
ON messages_read.message_id = messages.id
AND messages_read.[user_id] = #user_id
WHERE
messages_read.message_id IS NULL
Something like:
SELECT id, body FROM messages LEFT JOIN
(SELECT message_id FROM messages_read WHERE user_id = ?)
ON id=message_id WHERE message_id IS NULL
Slightly tricky and I'm not sure how the performance will scale up, but it should work.