MySQL query already GROUPed and ORDERed : how to ORDER inside the GROUPs? - mysql

I have this query:
SELECT id_user, COUNT(*) as count
FROM posts
GROUP BY id_user
ORDER BY COUNT(*) DESC
which gives me the id_user ordered by occurrences, and the number of each occurrence.
Can I get, in the same request, the LAST post from each 'id_user'? i.e. I want to select the last 'post' too, but when I do
SELECT id_user, post, COUNT(*) as count
Tthe value in 'post' isn't the last one (nor the first one; actually I don't know how groups are ordered). Should I run another query?

I believe u can accomplish this by adding max(post_id) last_post to your select.

This ought to do it in one query:
SELECT
p.id_user,
ap.post AS last_post,
COUNT(*) as count
FROM
posts p
JOIN posts ap on (
p.id_user = ap.id_user
AND ap.post_id = (
SELECT MAX(post_id) FROM posts ip WHERE p.id_user = ip.id_user
)
GROUP BY
p.id_user,
ap.post
ORDER BY
COUNT(*) DESC

Related

How to select single rows using MAX and GROUP BY on non-uniqe field in MySQL?

I came across this very simple case where I need to select a list of conversations from Conversations table along with latest message from Messages table - which has non-uniqe dateCreated field.
After long research I came up with this query:
SELECT
Conversations.id,
dateCreated,
`name`,
lastMessageId,
lastMessageDate,
lastMessagePayload
FROM Conversations
LEFT JOIN (
SELECT
id AS lastMessageId,
m1.conversationId,
payload AS lastMessagePayload,
m1.dateCreated AS lastMessageDate,
FROM Messages AS m1
INNER JOIN (
SELECT conversationId, MAX(dateCreated) AS mdate FROM Messages GROUP BY conversationId
) AS m2
ON m1.conversationId = m2.conversationId AND m1.dateCreated = m2.mdate
) AS msg2
ON msg2.conversationId = Conversations.id
ORDER BY dateCreated DESC
Query works well but if two latest messages in same conversation have exact same dateCreated field this query would then output two conversations with same id but different lastMessage... row of fields.
I just couldn't find a way to get around this problem as main problem is when you do GROUP BY a field and MAX on another non-uniqe field then you can't get out always only one row out.
Any idea how to get list of unique conversations with latest message (any message of the two if they have the same date)?
Use row_number()!
select c.*, m.* -- or whatever columns you want
from conversations c left join
(select m.*,
row_number() over (partition by m.conversationid order by m.dateCreated desc, m.id desc) as seqnum
from messages m
) m
on m.conversation_id = c.id and
m.seqnum = 1;
MySQL 5.x version...
Use a correlated sub-query to get the latest message id (for a given conversation), using ORDER BY and LIMIT 1
SELECT
Conversations.Conversations.id,
Conversations.dateCreated,
Conversations.`name`,
Messages.id AS lastMessageId,
Messages.payload AS lastMessagePayload,
Messages.dateCreated AS lastMessageDate,
FROM
Conversations
LEFT JOIN
Messages
ON Messages.id = (
SELECT lookup.id
FROM Messages AS lookup
WHERE lookup.conversationId = Conversations.id
ORDER BY lookup.dateCreated DESC
LIMIT 1
)
ORDER BY
Conversations.dateCreated DESC
In the event of two messages having the same date, the message you get is non-deterministic / arbitrary.
You could, if you wanted, therefore change it to get the highest id from the most recent date...
ORDER BY lookup.dateCreated DESC, lookup.id DESC
LIMIT 1

Order rows by amount of columns in another table

I'm currently outputting all of my members by adding the MySQL clause ORDER BY id DESC, but I feel that doesn't reward people that are active on my service.
I thought about judging the order by the amount of entries in another table they have under their ID.
Essentially, I'm asking if it's possible to order columns in a MAIN table counting the amount of rows where the users ID is in the column of the row.
Something pseudo to this
SELECT user_id,name,etc FROM users ORDER BY (
COUNT(SELECT FROM users_interactions WHERE user_id = user_id) *******
) ASC
In the end of the COUNT statement, the user_id = user_id was just a guess.
You are almost there - what you need to do is to put COUNT inside SELECT:
SELECT user_id,name,etc FROM users u ORDER BY (
SELECT COUNT(*)
FROM users_interactions i
WHERE i.user_id = u.user_id
) ASC
You could also do it using a JOIN, like this:
SELECT u.user_id, u.name, u.etc
FROM users u
LEFT OUTER JOIN users_interactions i ON i.user_id = u.user_id
GROUP BY u.user_id, u.name, u.etc
ORDER BY COUNT(*) ASC

MYSQL using other tables

This query:
SELECT
user_id,
count(base_item)
FROM items
WHERE base_item = '202'
group by user_id order by count(base_item)
Gives me this result:
which I want.
However, I also want it to exclude all user ids in the users table with a rank of 5 or greater. as shown here
Modify your where clause this way:
WHERE base_item = '202' AND user_id NOT IN (SELECT id FROM users WHERE rank > 5)
The portion in parentheses is called a subquery. The result set of the subquery contains the id of all users with a rank greater than 5. The addition to the where clause excludes all users in that result set.
Join with the users table and filter out rows with high rank
SELECT user_id, count(*) AS count
FROM items AS i
JOIN users AS u ON i.user_id = u.id
WHERE i.base_item = '202'
AND u.rank <= 5
group by user_id
order by count

Select last date and COUNT rows in a JOIN jquery?

I want to select the last inserted date and at the same time I want to select the user-name and count how many times the user-profile is visited.
So I am using this query
SELECT v.visitor_date, i.info_name, count(DISTINCT v.visitor_date) AS counted
FROM profile_visitors v
INNER JOIN profile_info i ON i.info_userId = v.visitor_accountId
ORDER BY v.visitor_date DESC
LIMIT 1
The result of the fiddle is wrong and SHOULD be
2015-07-28 11:05:16 - Testname - 5
Anyone knows what is wrong with the query?
http://sqlfiddle.com/#!9/2814c/1
DISTINCT does NOT give you the first or last record of any group, in fact you cannot guarantee which record DISTINCT will display within a group (nor does this matter by the way). So select MAX visitor date.
Try below query
SELECT MAX( v.visitor_date ) , i.info_name, COUNT( DISTINCT v.visitor_date ) AS counted FROM profile_visitors v INNER JOIN profile_info i ON i.info_userId = v.visitor_accountId ORDER BY v.visitor_date DESC LIMIT 1
You can try it:
SELECT v.visitor_date,
i.info_name,
COUNT(*) AS counted
FROM profile_visitors v
INNER JOIN profile_info i ON i.info_userId = v.visitor_accountId
GROUP BY v.visitor_accountId
ORDER BY v.visitor_date DESC
LIMIT 1

MySQL query with GROUP BY and ORDER BY timestamp DESC

I am saving the history of Facebook likes for a page, identified by user_id.
Now from this table, I need to get a set representing the user_id's and their latest number of likes, based on the most recent timestamp.
I started off with this:
SELECT *
FROM facebook_log
GROUP BY user_id
ORDER BY timestamp DESC;
But that does not do what I want because it returns the first records with the lowest timestamps.
I read something online about GROUP returning the very first records from the table.
I also understood something about JOIN the table with itself, but that doesn't work either, or I did something wrong.
If you just need the user_id and the timestamp, you can just do
select f.user_id, max(f.timestamp)
from facebook_log
group by user_id;
if you need all the data from the table, you can do
select f.*
from facebook_log f
inner join (select max(timestamp) mt, user_id
from facebook_log
group by user_id) m
on m.user_id = f.user_id and m.mt = f.timestamp
You can also get the latest number of likes by using this MySQL trick:
select f.user_id, max(f.timestamp),
substring_index(group_concat(f.numlikes order by f.timestamp desc), ',', 1) as LatestLikes
from facebook_log f
group by f.user_id;