ORDER BY before GROUP BY with JOIN - mysql

I have a problem with my SQL query. I want to display the last message for a user. So, i use the method "GROUP BY" but he don't display the LAST message.
This is my first query:
SELECT `messages`.*, `conversations`.*
FROM `messages` JOIN `conversations` ON `conversations`.`cNUM` = `messages`.`mCONV_NUM`
WHERE `cUSER2` = '2'
GROUP BY `messages`.`mCONV_NUMn`
I try to follow this subject: ORDER BY date and time BEFORE GROUP BY name in mysql (and a lot of other)
And i have this:
SELECT `messages`.*, `conversations`.*
FROM (SELECT mTIME
FROM `messages`
ORDER BY mTIME desc) AS M
JOIN `conversations` ON `conversations`.`cNUM` = `messages`.`mCONV_NUM`
WHERE `cUSER2` = '2'
GROUP BY `messages`.`mCONV_NUMn`
And i have this error: Table 'messages' unknown.
So.. i need your help guys

You gave an alias M to your messages table, as isaace said you shall refer to it as 'M' in the rest of the query as this temporary name lasts for the whole duration of the query and FROM is an initial phase in the query processing.
We are talking about something called logical query processing, this means that in
your query FROM statement is evaluated and processed initially and
then the rest of query.
In LQP terms queries will be processed in the following order.
FROM --> WHERE --> GROUP BY --> HAVING --> SELECT --> ORDER BY
(Of course I left out some phases but you get the idea)
Also you can use LIMIT to get the last message for a user.
Just add LIMIT 1 at the end.

You say you want the last message for a user, but it seems you really want several messages, namely their last message of each conversation they took part in.
For the lack of CROSS APPLY and window functions in MySQL, you need a query that does a lot of lookups to get the last message per conversation:
select *
from conversations c
join messages m on m.mconv_num = c.cnum
where c.cuser2 = 2
and not exists
(
select *
from messages m2
where m2.mconv_num = m.mconv_num
and m2.mtime > m.mtime
);

I want to display the last message for a user.
You get the one last message for a user with LIMIT:
select *
from conversations c
join messages m on m.mconv_num = c.cnum
where c.cuser2 = 2
order by m.mtime
limit 1;

Related

Get Conditionally Latest record from each group - without Aggregate functions or Partition

I have been trying to do this in many ways suggested.
Note: we do not want aggregate function or Partition since this is just a small part of whole Stored procedure and this is client requirement to not have it, so not in option and not possible duplicate of other existing answers / questions
I have a messages table, which has a column from and to, a foreign key to the user table, basically which user sends to whom at simplest. I also have other columns which are isSnoozed and snoozeAt for if the message is snoozed.
So the ordering is according to case. If messages is snoozed then consider snoozeAt time to Order or if not then consider sendAt. (right now we can ignore this condition while ordering, But I mentioned this since we cannot take simply MAX(id) )
I need to get recent most message from messages group by from user id
messages table like :
id -- to -- from -- isSnoozed -- snoozedAt -- sendAt ...
What I tried :
select * from ( select * from messages order by sendAt DESC) as TEMP GROUP BY TEMP.from
I tried many similar approaches but none worked.
I wasted many paid hours but can't find an approach which meets my exact requirement
NOTE: Please ignore typo in query if any, since I cant type in exact query table and names, So i typed in directly here
I figured this out by doing something like this, which could be explained in a simplified way:
select * from message where message.id in (
select
( select id from message where message.from = user.id order by CASE isSnoozed WHEN 0 THEN sendAt ELSE snoozeAt END DESC limit 1) as id
from user where user.id in ( select friends.`whoIsAdded` from friends where friends.`whoAdded` = myId)
) order by CASE isSnoozed WHEN 0 THEN sendAt ELSE snoozeAt END DESC
If I understand correctly, you just want the largest value in one of two columns. Assuming the values are never NULL, you can use greatest():
select m.*
from messages m
where greatest(m.sendAt, m.snoozedAt) =
(select max(greatest(m2.sendAt, m2.snoozedAt))
from messages m2
where m2.from = m.from
);
If the columns can be NULL, then you can use coalesce() to give them more reasonable values.

Why does MySQL query not return newest row

I got specific query:
SELECT *
FROM stats
WHERE mod_name = 'module'
GROUP BY domain
ORDER BY addition_date DESC
I want to retrive, the newest value for every domain. I know there is a domain x.com value with date 2014-02-19.
However, this query returns me row with date: 2014-01-06
That's quite simple query... why it does not take group by domains and take only newest value?
Am I missing something?
The order by takes place after the group by. That is why your query does not work. Here is a way to get what you want:
SELECT s.*
FROM stats s
WHERE mod_name = 'module' and
not exists (select 1
from stats s2
where s2.mod_name = s.mod_name and
s2.addition_date > s.addition_date
)
ORDER BY addition_date DESC;
To get the best performance, create an index on stats(mod_name, addition_date).

Unknown column 'wp_cons_users.id' in 'on clause'

I have three table one is for users and other one is for subject and third one contain user_id, subject_id foreign keys.
I get unknow coloumn when I run the following sql.
SELECT wp_cons_users.first_name, wp_cons_subject.subject, wp_cons_skilllist.skill_level
FROM `wp_cons_subject`
JOIN wp_cons_skilllist ON wp_cons_skilllist.user_id = wp_cons_users.id
JOIN wp_cons_users ON wp_cons_users.id = wp_cons_skilllist.user_id
WHERE wp_cons_subject.id = '1'
ORDER BY `wp_cons_skilllist`.`skill_level` DESC
I can't find the error with this query.
wp_cons_skilllist
column link to
id (primay)
user_id wp_cons_users -> id
subj_id wp_cons_subject -> id
skill_level
Here I try to get the username, skill level and subject for any given subject id.
Looks like your main problem is with the ordering of your JOINs. In your first join, you are matching with wp_cons_users.id, but you don't join that table until later in the query. If you re-order the joins it should work better. Also, based on your table description, it seems that you will also need to join on subject_id. This query should help:
SELECT wp_cons_users.first_name
, wp_cons_subject.subject
, wp_cons_skilllist.skill_level
FROM wp_cons_users
JOIN `wp_cons_subject`
ON wp_cons_users.id=`wp_cons_subject`.user_id
AND wp_cons_subject.id = '1'
JOIN
wp_cons_skilllist
ON wp_cons_skilllist.user_id = wp_cons_users.id
AND wp_cons_skilllist.subject_id = `wp_cons_subject`.id
ORDER BY `wp_cons_skilllist`.`skill_level` DESC
I am guessing about the field names that weren't in your original query, so you may have to make some changes if they're different from what I'm assuming.
Without information about your attributes in your table, I'm afraid we can only assume that there is no ID column in your wp_cons_users table.
when I corrected the query to following it started to work.
SELECT wp_cons_users.first_name, wp_cons_subject.subject, wp_cons_skilllist.skill_level
FROM `wp_cons_skilllist`
JOIN wp_cons_subject ON wp_cons_subject.id = wp_cons_skilllist.subject_id
JOIN wp_cons_users ON wp_cons_users.id = wp_cons_skilllist.user_id
WHERE wp_cons_skilllist.subject_id = '1'
ORDER BY `wp_cons_skilllist`.`skill_level` DESC
LIMIT 0 , 30

Return the data from the rows with the most recent date of each distinct candidate_id

I am attempting to return the data from the rows with the most recent date of each distinct candidate_id. It is correctly returning the most recent date (the created_unix column), but not the rest of the data from the corresponding row.
SELECT candidate_id, message, max(created_unix), jobpost_id, staffuserid
FROM messages
WHERE employer_id='$employerid' AND last='company'
GROUP BY candidate_id
You must group by everything not using an aggregate function:
SELECT candidate_id, message, max(created_unix), jobpost_id, staffuserid
FROM messages
WHERE employer_id='$employerid' AND last='company'
GROUP BY candidate_id, message, jobpost_id, staffuserid
If your message is different per row and you want to group by candidate_id, then you must not be using message. In that case, simply remove it from your select list and you won't need it in your group by list. The same goes for any other field you aren't using.
Remember, when using aggregate functions, you must contain each field in either an aggregate function or the group by. Otherwise, SQL won't know from which row to pull the data for the row returned.
Update:
After seeing what you're looking for, this will do the trick:
SELECT candidate_id, message, max(created_unix), jobpost_id, staffuserid
FROM messages
WHERE employer_id='$employerid' AND last='company' AND
created_unix = (
SELECT max(subm.created_unix)
FROM messages subm
WHERE subm.candidate_id = messages.candidate_id
)
SELECT m1.*
FROM messages as m1
LEFT OUTER JOIN messages AS m2
ON (m1.candidate_id = m2.candidate_id
AND (m1.created_unix < m2.created_unix)
WHERE m2.created_unix is NULL
AND employer_id='$employerid' AND last='company'
This joins messages to itself on candidate_id and makes rows with picks all dates in m2 that are greater than each date in m1, substituting NULL if none are greater. So you get NULL precisely when there is no greater date within that candidate_id.

How do I update the table(MYSQL)

the system throw a error "You can't specify target table 'screening' for update in FROM clause"
How do I completed the update like this?
UPDATE screening
SET maileddate = date('Y-m-d', strtotime($mailed_date[$screeningId]))
WHERE user_id IN (SELECT id FROM users
INNER JOIN screening ON
(users.id = screening.users_id
AND screening.id = {$screeningId}))
AND date BETWEEN 05-15/2011 AND 11-15-2011
LIMIT 2
You would have to remove the LIMIT option (similar to a TOP query in other SQL languages). You are basically saying find me the first 2 items and UPDATE. This may produce unexpected results on tables due to sort order.
Try putting the LIMIT clause in your SELECT subquery.