MySQL multiple group by using - mysql

Now i using this is query :
SELECT * FROM messages WHERE ReceiverID='$uid' or SenderID='$uid' GROUP BY Recei
verID,SenderID ORDER BY Datex DESC
But they results
ID ReceiverID SenderID
1 2 1
2 1 2
but i want to only showing one result for WHERE syntax.
for example:
ID ReceiverID SenderID
1 2 1
or
ID ReceiverID SenderID
2 1 2

You want to use least() and greatest():
SELECT *
FROM messages
WHERE ReceiverID='$uid' or SenderID='$uid'
GROUP BY least(ReceiverID, SenderID), greatest(ReceiverID, SenderID)
ORDER BY Datex DESC;
However, you should list the columns explicitly in the select. You are using a MySQL extension where you have columns in the select that are not in the group by. This is a bad idea unless you understand what you are really doing.

HI Try This query,
SELECT * FROM messages(SELECT * FROM messages ORDER BY Datex DESC) WHERE ReceiverID='$uid' or SenderID='$uid' GROUP BY ReceiverID,SenderID

If all you want is just one and it can be either one then why not just do a random ordering with a limit?
SELECT id, recieverid, senderid
FROM
( SELECT *
FROM messages
WHERE ReceiverID='$uid' OR SenderID='$uid'
GROUP BY ReceiverID,SenderID
ORDER BY Datex DESC
) t
ORDER BY RAND()
LIMIT 1

Related

Select sum of top three scores for each user

I am having trouble writing a query for the following problem. I have tried some existing queries but cannot get the results I need.
I have a results table like this:
userid score timestamp
1 50 5000
1 100 5000
1 400 5000
1 500 5000
2 100 5000
3 1000 4000
The expected output of the query is like this:
userid score
3 1000
1 1000
2 100
I want to select a top list where I have n best scores summed for each user and if there is a draw the user with the lowest timestamp is highest. I really tried to look at all old posts but could not find one that helped me.
Here is what I have tried:
SELECT sum(score) FROM (
SELECT score
FROM results
WHERE userid=1 ORDER BY score DESC LIMIT 3
) as subquery
This gives me the results for one user, but I would like to have one query that fetches all in order.
This is a pretty typical greatest-n-per-group problem. When I see those, I usually use a correlated subquery like this:
SELECT *
FROM myTable m
WHERE(
SELECT COUNT(*)
FROM myTable mT
WHERE mT.userId = m.userId AND mT.score >= m.score) <= 3;
This is not the whole solution, as it only gives you the top three scores for each user in its own row. To get the total, you can use SUM() wrapped around that subquery like this:
SELECT userId, SUM(score) AS totalScore
FROM(
SELECT userId, score
FROM myTable m
WHERE(
SELECT COUNT(*)
FROM myTable mT
WHERE mT.userId = m.userId AND mT.score >= m.score) <= 3) tmp
GROUP BY userId;
Here is an SQL Fiddle example.
EDIT
Regarding the ordering (which I forgot the first time through), you can just order by totalScore in descending order, and then by MIN(timestamp) in ascending order so that users with the lowest timestamp appears first in the list. Here is the updated query:
SELECT userId, SUM(score) AS totalScore
FROM(
SELECT userId, score, timeCol
FROM myTable m
WHERE(
SELECT COUNT(*)
FROM myTable mT
WHERE mT.userId = m.userId AND mT.score >= m.score) <= 3) tmp
GROUP BY userId
ORDER BY totalScore DESC, MIN(timeCol) ASC;
and here is an updated Fiddle link.
EDIT 2
As JPW pointed out in the comments, this query will not work if the user has the same score for multiple questions. To settle this, you can add an additional condition inside the subquery to order the users three rows by timestamp as well, like this:
SELECT userId, SUM(score) AS totalScore
FROM(
SELECT userId, score, timeCol
FROM myTable m
WHERE(
SELECT COUNT(*)
FROM myTable mT
WHERE mT.userId = m.userId AND mT.score >= m.score
AND mT.timeCol <= m.timeCol) <= 3) tmp
GROUP BY userId
ORDER BY totalScore DESC, MIN(timeCol) ASC;
I am still working on a solution to find out how to handle the scenario where the userid, score, and timestamp are all the same. In that case, you will have to find another tiebreaker. Perhaps you have a primary key column, and you can choose to take a higher/lower primary key?
Query for selecting top three scores from table.
SELECT score FROM result
GROUP BY id
ORDER BY score DESC
LIMIT 3;
Can you please try this?
SELECT score FROM result GROUP BY id ORDER BY score DESC, timestamp ASC LIMIT 3;
if 2 users have same score then it will set order depends on time.
You can use a subquery
SELECT r.userid,
( SELECT sum(r2.score)
FROM results r2
WHERE r2.userid = r.userid
ORDER BY score DESC
LIMIT 3
) as sub
FROM result r
GROUP BY r.userid
ORDER BY sub desc
You should do it like this
SELECT SUM(score) as total, min(timestamp) as first, userid FROM scores
GROUP BY userid
ORDER BY total DESC, first ASC
This is way more efficient than sub queries. If you want to extract more fields than userid, then you need to add them to the group by.
This will of cause not limit the number of scores pr user, which indeed seems to require a subquery to solve.

sort on two parameters

I have a table with checkin records like this:
userID checkin_date
1 '2014-01-28 08:00:00'
1 '2014-01-27 09:10:00'
1 '2014-01-26 12:24:00'
2 '2014-01-26 08:17:00'
3 '2014-01-26 09:33:00'
2 '2014-01-28 10:28:00'
.. .........
and i want with a single request sort the ten users who checkin the most since a specific date (order by nb visite DESC) (that easy) but for each one i also want to know the date of their last checkin.
i do something like this:
SELECT
userID,
count(*) as nbVisit,
checkin_date
FROM(
SELECT
userID,
checkin_date
FROM checkin_table
WHERE checkin_date > '2014-01-25'
ORDER BY checkin_date DESC )as sub
GROUP BY userID
ORDER BY nbVisit DESC
LIMIT 10
is it the best way to do it ? will it work in any time ? is it efficient with lots of data ?
SQLFIDDLE
You don't need a subquery for this, just use max() along with count(*):
SELECT userID, max(checkin_date), count(*) as nbVisit,
FROM checkin_table
WHERE checkin_date > '2014-01-25'
GROUP BY userId
ORDER BY nbVisit desc
LIMIT 10 ;

How to select from a selection?

I'm creating a commenting system, which will have 2 top comments.
How can I select the latest 20 rows, and then from that selection, select the top 2 rows (likes-dislikes)? I can do it with a PHP loop, but it would not be as efficient. Currently I am just selecting the top 2 from the all the comments, but the two top comments never change, since people just up-vote those ones:
SELECT * FROM pagecomments WHERE page_id='$pageid' ORDER BY likes-dislikes DESC LIMIT 2
EDIT: The table is ordered by the the column "id", which is auto_increment. page_id is the page on the site. Sorry.
Nest your query:
SELECT *
FROM (
SELECT *
FROM pagecomments
WHERE page_id='$pageid'
ORDER BY date DESC
LIMIT 20
) t
ORDER BY likes-dislikes DESC
LIMIT 2
Order not only by LIkes, first order by date entered or timestamp. By ordering by date, you assure that you`ll get the latest 20 posts or comments.
SELECT * FROM pagecomments WHERE page_id='$pageid' ORDER by date_entered desc ,
likes-dislikes DESC limit 2
Since your id column is set to auto_increment, use it in a subquery:
select *, likes-dislikes
from (
select *
from pagecomments
where page_id='$pageid'
order by id desc
limit 20
) t
order by likes-dislikes desc
limit 2
Condensed SQL Fiddle Demo

How to find user with MOST rows in table - mysql?

If you have a column called userID, what query would you use to find the userID with the greatest number of rows in that table?
Thank you
You can use COUNT, ORDER BY that count DESC and LIMIT the result to the top one:
SELECT user_id, COUNT(*)
FROM tableName
GROUP BY user_id
ORDER BY 2 DESC
LIMIT 1;
select user_id, sum(1) as counter
from TABLE
group by user_id
order by 2 desc
limit 1
This should be enough to get only one user, even if more than one user share the maximum amount of rows:
SELECT user_id FROM table
GROUP BY user_id
ORDER BY COUNT(*) DESC
LIMIT 1
If you need to return all matching users:
SELECT user_id FROM table
GROUP BY user_id
HAVING COUNT(*) = (
SELECT COUNT(*) FROM table
GROUP BY user_id
ORDER BY COUNT(*) DESC
LIMIT 1
)

Mysql select first then limit

How can i select the newest 5 rows from mysql (newest by id for example) then order them asc or desc ??
the problem is i have 1,2,3,4,5,6,7 , i want to select the newest 2 for example (6,7) then order them asc or desc (6,7 or 7,6) , but if i use the orderby then the limit it would be (1,2) or (7,6) , is there anyway to do it from ONE sql statement ?
thank you
You may use something like
SELECT * FROM TABLE WHERE ID IN (SELECT ID FROM TABLE WHERE X ORDER BY ID LIMIT 2) ORDER BY ID DESC
I didn't get if you wanted the newest 5 or 2, I use 2 here. But here is something I just wrote without testing.
SELECT * FROM table WHERE id IN (SELECT id FROM table ORDER BY id DESC LIMIT 2) ORDER BY id ASC/DESC;
Hope this will help! :)
ok i found the solution , thank you all for your efforts and answers ,
i made 2 columns , ID and TSTAMP (for timestamp) , just made it like order by id asc , tstamp asc/desc ... limit x , so it orders always by the id then orders by the tstamp and limits the right thing .
and nested queries are a pain for the engine ...
thanks
Select * from TABLE order by id asc , time_stamp desc
Why can't you do something such as
SELECT *
FROM TABLE
WHERE (TABLE.primary_key IN (
SELECT TABLE.primary_key
FROM TABLE
ORDER BY TABLE.id ASC
LIMIT 2
))
ORDER BY TABLE.id DESC