sort on two parameters - mysql

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 ;

Related

MySQL count results after MAX timestamp

I have two tables
mts
id
customer_id
created_at
mos
id
customer_id
created_at
I want to get the last time of an entry in mts and count the results of mos after MAX(mts.created_at). All should be GROUP BY customer_id.
I had the idea of a simple query like this, but this wont work.
SELECT id, created_at, COUNT(id)
FROM mos
WHERE created_at > (SELECT MAX(created_at) FROM mts)
GROUP BY customer_id
LIMIT 10
This SQL-Statement will just give you 1 single line in the result set (not matter what). Everything that is not part of an aggregate-function should by contained in GROUP BY.
Your SQL-Statement should look like this:
SELECT id, created_at, COUNT(id)
FROM mos
WHERE created_at > (SELECT MAX(created_at) FROM mts)
GROUP BY customer_id, id, created_at
LIMIT 10

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.

MySQL multiple group by using

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

Retrieve the second latest record with same id

From the following four records, I want to select the OwnerId of second-latest record
ItemId OwnerId Date
11477 20981 2013-05-13
11477 1 2013-05-21
11477 21086 2013-05-22 #this is the one I'm talking about
11477 3868 2013-05-24
How to go about it?
This needs ItemID to be specified,
SELECT *
FROM TableName
WHERE ItemID = '11477'
ORDER BY DATE DESC
LIMIT 1,1
SQLFiddle Demo
However, if you don't want to specify the ItemID, and you want to get all second latest record for every ItemID, you can use a correlated subquery to generate a sequence number for every ItemID based on lastest DATE,
SELECT ItemId, OwnerID, Date
FROM
(
SELECT A.ItemId,
A.OwnerId,
A.Date,
(
SELECT COUNT(*)
FROM tableName c
WHERE c.ItemId = a.ItemId AND
c.Date >= a.Date) AS RowNumber
FROM TableName a
) x
WHERE RowNumber = 2
SQLFiddle Demo
select ownerid
from your_table
order by date desc
limit 1, 1
I think you can just to ORDER BY date descending, which will give you an order from newer to older, then LIMIT 1,1 to get only the second result, which should be the one you look for
SELECT *
FROM table
ORDER BY date DESC
LIMIT 1,1

Most common number in MYSQL SELECT statement

I am trying to get a MYSql statement to spit out the most common number in a field. I believe I am supposed to use COUNT(QUANTITY) but I am confused by which to GROUP BY and ORDER BY, I can't seem to get the correct MODE (Most common number).
*EDIT*
Here is a sample table:
QUANTITY | ORDER_NUMBER
1 51541
4 12351
5 11361
5 12356
6 12565
8 51424
10 51445
25 51485
The MYSql statement should spit out the number 5 because it appears most often
SELECT QUANTITY,COUNT(*)
FROM ...
GROUP BY 1
ORDER BY 2 DESC
LIMIT 1;
SELECT ORDER_NUMBER AS ORDER, COUNT(QUANTITY) as numorders
FROM table
GROUP BY ORDER_NUMBER
ORDER BY numorders
to get the top 10 order_numbers do
select order_number, count(order_number) as quantity
from your_table
group by order_number
order by quantity desc
limit 10
SELECT QUANTITY, COUNT(QUANTITY) AS TOTAL_Q
FROM MYTABLE
GROUP BY QUANTITY
ORDER BY TOTAL_Q DESC
this will give you number of quanity from most to least number....