I'm working on a messaging app and trying to reduce the amount of queries but running into some trouble trying to get the context for message replies. Currently, when a message is a reply, I'm saving the ID of the message it's replying to a column called replying, and fetching it as an additional query after the fact.
For example, this is my current query.
SELECT id, message, time, user, replying
FROM messages
WHERE conversation = ?
ORDER BY ai DESC
LIMIT 50
Ideally I'd like it to also SELECT id, message, time, user WHERE id = previous.replying when applicable.
Is this possible?
Related
I've tried about a dozen different methods to solve this issue, and everything I try is breaking my query... I have the following code that is used to generate a loop of threads on a message board:
SELECT MB_TOPICS.*, MAX(MB_REPLIES.TIMESTAMP) AS LATEST
FROM MB_TOPICS
LEFT JOIN MB_REPLIES
ON MB_TOPICS.TOPIC_ID = MB_REPLIES.TOPIC_ID
WHERE MB_TOPICS.CATEGORY_ID='$CATEGORY'
GROUP BY MB_TOPICS.TOPIC_ID
ORDER BY MB_TOPICS.STICKY DESC, LATEST DESC, MB_TOPICS.TIMESTAMP DESC
LIMIT $start,$limit";
This is basically pulling all of the topics within the category, and then via a join it is also getting a timestamp of the most recent reply (if any) from the replies table.
On the sort, I want to keep the most recently active threads at the top... currently (after sticky Y/N) it's sorting by most recent reply and then by the timestamp when the thread was created... this is wrong because it means a new thread will appear after an old thread with replies. I've tried things like
GREATEST(LATEST, MB_TOPICS.TIMESTAMP)
or using IIF statements, CASE statements within the ORDER BY, etc., but anything I do is just breaking the query so that no results appear. I just want to make this so that whichever timestamp is most recent (last reply or topic creation), it sorts descending on that largest value. I know this must be simple but it's killing me today. Thank you!
Edit: If it's helpful information here... the 'LATEST' column will be null for threads that have no replies...
OK, I finally got it. I had to use the MAX() function again rather than the alias, and coalesce to deal with the null values, combined with RiggsFolly's suggestion of pulling it as a new column, resulted in this functioning query:
"SELECT MB_TOPICS.*, MAX(MB_REPLIES.TIMESTAMP) AS LATEST,
GREATEST(COALESCE(MAX(MB_REPLIES.TIMESTAMP),0), MB_TOPICS.TIMESTAMP) AS SORT_ORDER
FROM MB_TOPICS
LEFT JOIN MB_REPLIES ON MB_TOPICS.TOPIC_ID = MB_REPLIES.TOPIC_ID
WHERE MB_TOPICS.CATEGORY_ID='$CATEGORY'
GROUP BY MB_TOPICS.TOPIC_ID
ORDER BY MB_TOPICS.STICKY DESC, SORT_ORDER DESC
LIMIT $start,$limit";
Thanks, I wouldn't have gotten there without the discussion here.
Lets say I have a simple table with 'appID' and 'userID', which his populated for each app that used by a specific user (ever). (These IDs refer to other tables which have information about app and user which do not matter for this question).
For example:
appID userID
1 1
1 2
2 2
Here, we can see app #1 was used by two users, but app #2 was used by one user.
I want to generate statistics for the most commonly used app using a MySQL query, if possible. The query would return a list of sorted results with the appID and the total number of unique users using it.
I did some research but cannot figure out an easy to do this in SQL. If anyone can help, I'd appreciate it. If it requires a very long and involved stored procedure, I may just switch to doing some of the calculations in code (at least initially) since it will be easier to troubleshoot.
SELECT appID, COUNT(*) FROM myTable GROUP BY appID ORDER BY COUNT(*) DESC
I fail at mysql, and could really do with some help. I don't know what it would be called, and all my attempts at using combinations of DISTINCT and GROUP BY are just not working out.
I have a table of server monitoring data with these columns:
nStatusNumber
Bandwidth
Load
Users
ServerNumber
DiskFree
MemFree
TimeStamp
**nStatusNumber** - A unique number increasing for each entry
**ServerNumber** - A unique number for each server
For the top of my dashboard for this, I need to display the most recent report for each unique server.
// How many servers are we monitoring ?
$nNumServers = mysql_numrows(mysql_query("SELECT DISTINCT(ServerNumber) FROM server_status;"));
// Get our list of servers
$strQuery = "SELECT * FROM server_status ORDER BY nStatusNumber DESC limit ".$nNumServers.";";
And then loop through the results until we hit $nNumServers . This worked at first, until servers started going down/up and the report order got jumbled.
Say theres 20 servers, the most recent 20 results aren't necessarily 1 from each server.
I'm trying to figure this out in a hurry, and failing at it. I've tried all sorts of combinations of DISTINCT and GROUP BY with no luck so far and would appreciate any guidance on what's probably an embarrassingly easy problem that I just can't see the answer to.
Thanks!
PS - Here's an example query that I've been trying, showing the problem I'm having. Check the "nStatusNumber" field, these should be showing the most recent results only for each server - http://pastebin.com/raw.php?i=ngXLRhd6
PPS - Setting max(nStatusNumber) doesn't give accurate results. I don't want some average/sum/median figure, I need the most recent ACTUAL figures reported by each server. Heres more example results for the queries:
http://pastebin.com/raw.php?i=eyuPD7vj
For your purpose you need to find the row unique to a nServerNumber and TimeStamp. This is not as simple as just saying MAX(TimeStamp) as you need to find the row corresponding to it.
Although I am not an expert in SQL you can try this and see if it works.
SELECT A.nServerNumber, A.nStatusNumber, A.nVNStatsBandwidth, A.fLoad, A.nUsers,
A.nUsersPaid, A.nServerNumber, A.nFreeDisk, A.nTotalDisk, A.nFreeMemory,
A.nTotalMemory, A.TimeStamp
FROM server_status A
INNER JOIN
(
SELECT nServerNumber, MAX(TimeStamp) as `TimeStamp`
FROM server_status
GROUP BY nServerNumber
) B
ON A.nServerNumber = B.nServerNumber
AND A.TimeStamp = B.TimeStamp
ORDER BY A.nServerNumber ASC;
This query will give you all the servers with their latest info. So if you want the total number of servers just run the mysql_numrows(...) function on this result and if you want the data just iterate through the same result (no need to fire two separate SQL queries).
Try this ::
Select
Select MAX(nStatusNumber) from table,
Bandwidth,
Load,
Users,
ServerNumber,
DiskFree,
MemFree,
MAX(`TimeStamp`)
from your table
group by ServerNumber
Here is my code:
mysql_query("SELECT * FROM messages WHERE to_user_id = '$user_id' GROUP BY from_user_id ORDER BY read,sent_date DESC")
and here is my table structure
I use the GROUPY BY from_user_id statement to briefly show a list of "conversations" instead of every single message. Like this
But, as you can see in the image, the top two are the wrong way round, the first one says "1 week ago" and the one below says "2 days ago". The reason for these being in the wrong order is due to the GROUP BY from_user_id statement. Because it groups all the messages from that user and it wont have the the most recent time on it.
So my question is:
How can I GROUP BY from_user_id by the most recent record?
You can not SELECT columns not listed in the GROUP BY or otherwise allowed functions. This is how GROUP BY works.
Although most other SQL flavors would fail on such a query, MySQL doesn't. Instead it provides arbitrary results - what you are seeing.
You can solve this a few different ways. For example:
SELECT the ids of the latest user conversations using GROUP BY in a separate query.
Do it all in one query by sub-selecting the ids or JOIN the set of ids.
Since MySQL doesn't support windowing functions like ROW_NUMBER() OVER() you can do something like this:
SELECT *
FROM Messages
where id in (SELECT MAX(ID) FROM messages GROUP BY from_user_id)
ORDER BY sent_date, read
The subquery will only return the newest message id for each user. I'm assuming your auto_increment corresponds with the order the messages are sent in. Even if it's not the exact logic you might want, this is a general technique to get a specific subset of values from grouped records that works in MySQL.
Try with this
SELECT *,MAX(id) as OrderField FROM messages WHERE to_user_id = '$user_id'
GROUP BY from_user_id
ORDER BY OrderField DESC,read
I have a database that gets a new row added for every time a user logs into the system. What I would like to be able to do is first to make a query that gets the distinct entries by the hashed user ids. This I can do. SELECT DISTINCT is our friend it seems. After this, however, I would still like to be able to get a count, per user id, of how many times people logged in.
For instance, if Max logged in 3 times and Sally logged in 2 times I would have five rows in my DB. After running SELECT DISTINCT by their user ids it would just give me one Max and one Sally user id. After having this information, however, I'd like to be able to create a hash, map, whatever, that stores the following information:
Max => 3
Sally => 2
Is there a way using pure, or mostly pure, SQL that this could be achieved in an efficient manner or should I simply get out ALL of the login db rows and search and compile the information myself. I know I could do it this way but somehow that feels slower. Thanks
You can do this in SQL using the "GROUP BY" operator. For example:
SELECT user_id, count(*) FROM USERS GROUP BY user_id
SELECT username,COUNT(*) AS LoginCount FROM logintable GROUP BY username
SELECT login, COUNT(login) FROM yourtable GROUP BY login
Sure...
select
hashed_user_id, count(*)
from
table name
group by hashed_user_id
the answer could be more specific if you give tabl structure:
however, this is typically an aggregate function with a group by - something like this:
select user, count(user)
from access_log
group by user
Trying to do a count like you're saying is an unecessary overhead. My advice would be to add an extra field in your users table 'logincount' and +1 every time a user logs in. Much quicker.