I have a mySQL database table I'm using to store messages sent out to people. Each message can contain points. I am wondering if there is a query that would sum up all the points per person and order them by rank?
Currently the only way I know how to get the output I'm looking for is to run this:
SELECT SUM(messagePoints) AS totalPoints FROM Messages
then store the result in PHP and order the result by totalPoints. I'm sure there is a way to do this entirely with a query but I don't have a clue where to start. Hoping somebody can give me some advice.
Messages Table example
messageID | personID | dateOfMessage | messagePoints
----------------------------------------------------------------
1 | 10 | 2017-01-05 00:00:00 | 5
2 | 10 | 2017-01-16 00:00:00 | 3
3 | 20 | 2017-01-16 00:00:00 | 4
4 | 10 | 2017-02-01 00:00:00 | 6
5 | 20 | 2017-02-07 00:00:00 | 7
Ideal Result:
personID | totalPoints | rank
--------------------------------
10 | 14 | 1
20 | 11 | 2
If the above output is possible, I'm wondering if it is possible to produce the same output with a date range filter such as only messages from the month of February.
Ideal Result only February messages:
personID | totalPoints | rank
--------------------------------
20 | 7 | 1
10 | 6 | 2
EDIT:
If it's easier, I ultimately need to display in my application the totalPoints and rank for 1 person (to be supplied by PHP) i.e. just results for personID = 10 I need both totalPoints and rank overall and filtered by date. So maybe 4 separate queries.
Ideal Overall Result for personID=10:
totalPoints
-----------
14
and
rank
----
1
Ideal Result for personID=10 Filtered by February:
totalPoints
-----------
6
and
rank
----
2
If you don't need the rank in the result - this is a basic aggregation query:
select m.personID, sum(messagePoints) as totalPoints
from messages m
group by m.personID
order by totalPoints desc
One way to include a row number (rank) to the result is to use a temporary table with an AUTO_INCREMENT column for the rank:
drop temporary table if exists tmp_messages;
create temporary table tmp_messages(
rank int auto_increment primary key,
personID int,
totalPoints int
) as
select null as rank, m.personID, sum(messagePoints) as totalPoints
from messages m
group by m.personID
order by totalPoints desc;
select * from tmp_messages order by rank;
You can ofcourse include fllters in the WHERE clause like:
select m.personID, sum(messagePoints) as totalPoints
from messages m
where m.dateOfMessage >= '2017-02-01'
and m.dateOfMessage < '2017-03-01'
group by m.personID
And you can select a specific user:
select * from tmp_messages where personID = 10
Demo: http://rextester.com/ASWF7717
You can try the below code to get the rank and you can use where clause to filter for dates.
select personID, SUM(messagePoints) AS totalPoints,#curRank := #curRank + 1 AS rank
from Messages, (select #curRank :=0) r
group by personID
order by totalPoints
Related
help please make sql select to database. There are such data.
My table is:
id news_id season seria date_update
---|------|---------|-----|--------------------
1 | 4 | 1 | 7 | 2017-04-14 16:38:10
2 | 4 | 1 | 7 | 2017-04-14 17:38:10
5 | 4 | 1 | 7 | 2017-04-14 16:38:10
3 | 4 | 1 | 7 | 2017-04-14 16:38:10
4 | 4 | 1 | 7 | 2017-04-14 16:38:10
6 | 4 | 1 | 7 | 2017-04-14 16:38:10
7 | 4 | 1 | 7 | 2017-04-14 16:38:10
8 | 1 | 1 | 25 | 2017-04-23 18:42:00
Need to get all cells grouped by max season and seria and date and sorted by date_update DESC.
In result i need next rows
id news_id season seria date_update
---|------|---------|-----|--------------------
8 | 1 | 1 | 25 | 2017-04-23 18:42:00
2 | 4 | 1 | 7 | 2017-04-14 17:38:10
Because this rows have highest season and seria and date_update per One news_id. I.e i need to select data wich have highest season and seria and date_update grouped by news_id and also sorted by date_update DESC
I tried so, but the data is not always correct, and it does not always for some reason cover all the cells that fit the condition.
SELECT serial.*
FROM serial as serial
INNER JOIN (SELECT id, MAX(season) AS maxseason, MAX(seria) AS maxseria FROM serial GROUP BY news_id) as one_serial
ON serial.id = one_serial.id
WHERE serial.season = one_serial.maxseason AND serial.seria = one_serial.maxseria
ORDER BY serial.date_update
Please, help. Thank.
The specification is unclear.
But we do know that the GROUP BY news_id clause is going collapse all of the rows with a common value of news_id into a single row. (Other databases would throw an error with this syntax; we can get MySQL to throw a similar error if we include ONLY_FULL_GROUP_BY in the sql_mode.)
My suggestion would be to remove the GROUP BY news_id clause from the end of the query.
But that's just a guess. It's not at all clear what you are trying to achieve.
EDIT
SELECT t.*
FROM (
SELECT r.news_id
, r.season
, r.seria
, MAX(r.date_update) AS max_date_update
FROM (
SELECT p.news_id
, p.season
, MAX(p.seria) AS max_seria
FROM (
SELECT n.news_id
, MAX(n.season) AS max_season
FROM serial n
GROUP BY n.news_id
) o
JOIN serial p
ON p.news_id = o.news_id
AND p.season = o.max_season
) q
JOIN serial r
ON r.news_id = q.news_id
AND r.season = q.season
AND r.seria = q.max_seria
) s
JOIN serial t
ON t.news_id = s.news_id
AND t.season = s.season
AND t.seria = s.seria
AND t.date_update = s.max_date_update
GROUP BY t.news_id
ORDER BY t.news_id
Or, an alternate approach making use of MySQL user-defined variables...
SELECT s.id
, s.season
, s.seria
, s.date_update
FROM (
SELECT IF(q.news_id = #p_news_id,0,1) AS is_max
, q.id
, #p_news_id := q.news_id AS news_id
, q.season
, q.seria
, q.date_update
FROM ( SELECT #p_news_id := NULL ) r
CROSS
JOIN serial q
ORDER
BY q.news_id DESC
, q.season DESC
, q.seria DESC
, q.date_update DESC
) s
WHERE s.is_max
ORDER BY s.news_id
The subquery selects the maximum season and the maximum seria per news_id. How many records exist for the news_id that match both the maximum season and the maximum seria we don't know. It can be, one or two or thousand or zero.
So with the join you get an unknown number of records per news_id. Then you group by news_id. This gets you one result row per news_id. How then can you select serial.*? * means all columns from a row, but which row,when there can be many for a news_id? MySQL usually picks values arbitrarily in this case (usually all from the same row, but even that is not guaranteed). So you end up with random rows which you order by date_update.
This doesn't make much sense. So the question is: what do you really want to achieve? Maybe my explanation suffices and you are able now to fix your query yourself.
I'm trying to return back all the messages for a user_id ( 1 ) in the table sorted by created_at desc, but have it grouped by sender_id or recipient_id depending on whichever created_at is newer.
messages
sender_id | recipient_id | text | created_at
1 | 2 | hey | 2017-03-26 04:00:00
1 | 2 | tees | 2017-03-26 00:00:00
2 | 1 | rrr | 2017-03-27 00:00:00
3 | 1 | edd | 2017-03-27 00:00:00
1 | 3 | cc3 | 2017-02-27 00:00:00
Ideally it would return
2 | 1 | rrr | 2017-03-27 00:00:00
1 | 3 | cc3 | 2017-02-27 00:00:00
The query I have so far is -
select *
from messages
where (
sender_id = 1
or recipient_id = 1
)
group by least(sender_id, recipient_id)
order by created_at desc
but it seems it is doing the order by before the group by.
Any help would be appreciative.
GROUP BY is intended for aggregation (sum, count, etc...), the fact that it orders is little more than an official side effect (that is being deprecated, and not guaranteed behavior in future versions). ORDER BY is done after GROUP BY, it sorts the final results, and can take multiple expressions. Your interchangeable use of the terms makes it difficult to understand exactly what you are looking for, but going by sample desired results this is probably it:
ORDER BY LEAST(sender_id, recipient_id), created_at DESC
However, since all rows in your sample result have the same "LEAST" value, it could be this:
ORDER BY LEAST(sender_id, recipient_id), created_at DESC
If you are attempting to get the most recent post by user 1 where they are a sender and the most recent post by user 1 where they are a recipient.
I would do a union with the first query getting the most recent post as a sender and the second getting the most recent post as a recipient.
select *
from messages
join
(
select
sender_id,
max(created_at) as max1
from messages
where
sender_id = 1
group by
sender_id
) t1
on messages.created_at = t1.max1
union
select *
from messages
join
(
select
recipient_id,
max(created_at) as max2
from messages
where
recipient_id = 1
group by
recipient_id
) t2
on messages.created_at = t2.max2
Note: I'm not sure if I gave this question the most leading title since I'm not sure on the correct approach towards this, but I couldn't find other examples anywhere since it's quite a specific query.
So, I have a table "votes", which is filled with votes created by users (uniquely identified as a number in the user_id column) which correspond to relevent posts in another table (vote records "upvote" each relevent post within the user interface).
I intend to sort these votes (by datetime) in order of latest vote created for each post (post_id column), and as such, avoiding duplicate returned values of each post_id.
I input the following query:
SELECT id, user_id, post_id, created, MAX(created)
FROM votes
GROUP BY post_id, user_id
ORDER BY max(created) DESC
And get returned:
Table: votes
id | user_id | post_id | created | MAX(created)
----+-----------+-----------+-----------------------+--------------------
115 | 1 | 42 | 2014-07-03 23:08:31 | 2016-03-07 12:08:31
----+-----------+-----------+-----------------------+--------------------
237 | 2 | 101 | 2014-02-13 23:05:14 | 2016-03-05 23:05:14
----+-----------+-----------+-----------------------+--------------------
431 | 7 | 944 | 2014-10-22 22:58:37 | 2016-03-03 19:58:37
----+-----------+-----------+-----------------------+--------------------
255 | 15 | 101 | 2014-02-15 14:02:01 | 2016-02-01 23:05:14
----+-----------+-----------+-----------------------+--------------------
... | ... | ... | ... | ...
As you can see, there is a duplicate of the post_id "101". The result of this query seems to sort by maximum created time for each user_id, showing duplicated post_id's, e.g. there are two post_id column rows of "101", when I would only like to diplay the only post_id column value of "101" which has the maximum created time (MAX(created)).
The post_id and user_id columns seemingly must be grouped together, else if I just group by post_id I'm unable to sort by MAX(created) since it won't return the max(created) for each post_id.
How do I remove these duplicated post_id values that don't return the maximum created time?
What I'm after:
Table: votes
id | user_id | post_id | created | MAX(created)
----+-----------+-----------+-----------------------+--------------------
115 | 1 | 42 | 2014-07-03 23:08:31 | 2016-03-07 12:08:31
----+-----------+-----------+-----------------------+--------------------
237 | 2 | 101 | 2014-02-13 23:05:14 | 2016-03-05 23:05:14
----+-----------+-----------+-----------------------+--------------------
431 | 7 | 944 | 2014-10-22 22:58:37 | 2016-03-03 19:58:37
----+-----------+-----------+-----------------------+--------------------
... | ... | ... | ... | ...
Assuming you only want the last vote for each post:
SELECT v.*
FROM posts p
JOIN votes v
ON v.id =
(
SELECT id
FROM votes vi
WHERE post_id = p.id
ORDER BY
created DESC
LIMIT 1
)
If you are looking for getting last user_id whom edited post_id, try group by post_id and ordering by time desc (or id if it is auto increment).
SELECT tbl.* , GROUP_CONCAT('(',tbl.user_id,',',tbl.created,')') as myhistory FROM
(SELECT id, user_id, post_id, created, MAX(created)
FROM votes
ORDER BY max(created) DESC
) as tbl
GROUP BY tbl.post_id
If you need history for (user_id,time) you can use group_concat function as mentioned in code for myhistory column.
SELECT maintable.*
FROM TABLE_NAME maintable
LEFT OUTER JOIN TABLE_NAME temporarytable
ON maintable.GROUPING_BY_COLUMN = temporarytable.GROUPING_BY_COLUMN
AND maintable.COLUMN_WHERE_THE_MAXIMUM_IS_NEEDED < temporarytable.COLUMN_WHERE_THE_MAXIMUM_IS_NEEDED
WHERE temporarytable.COLUMN_WHERE_THE_MAXIMUM_IS_NEEDED IS NULL
ORDER BY PRIMARY_KEY_COLUMN DESC
LIMIT 50;
An alternative way to get the maximum value from a group. This query does not require aggregation, as is the case with “GROUP BY”.
In addition, when grouping using “GROUP BY”, each of the groups is sorted by primary key, which also takes a lot of time.
My query compares the values of one table with another. Until he can find nothing more. If nothing else is found, then this is the maximum.
This query can help you save time getting the maximum value from the group.
I am trying to construct a highscore table from entries in a table with the layout
id(int) | username(varchar) | score(int) | modified (timestamp)
selecting the highest scores per day for each user is working well using the following:
SELECT id, username, MAX( score ) AS hiscore
FROM entries WHERE DATE( modified ) = CURDATE( )
Where I am stuck is that in some cases plays may achieve the same score multiple times in the same day, in which case I need to make sure that it is always the earliest one that is selected because 2 scores match will be the first to have reached that score who wins.
if my table contains the following:
id | username | score | modified
________|___________________|____________|_____________________
1 | userA | 22 | 2014-01-22 08:00:14
2 | userB | 22 | 2014-01-22 12:26:06
3 | userA | 22 | 2014-01-22 16:13:22
4 | userB | 15 | 2014-01-22 18:49:01
The returned winning table in this case should be:
id | username | score | modified
________|___________________|____________|_____________________
1 | userA | 22 | 2014-01-22 08:00:14
2 | userB | 22 | 2014-01-22 12:26:06
I tried to achieve this by adding ORDER BY modified desc to the query, but it always returns the later score. I tried ORDER BY modified asc as well, but I got the same result
This is the classic greatest-n-per-group problem, which has been answered frequently on StackOverflow. Here's a solution for your case:
SELECT e.*
FROM entries e
JOIN (
SELECT DATE(modified) AS modified_date, MAX(score) AS score
FROM entries
GROUP BY modified_date
) t ON DATE(e.modified) = t.modified_date AND e.score = t.score
WHERE DATE(e.modified) = CURDATE()
I think this would works for you and is the simplest way:
SELECT username, MAX(score), MIN(modified)
FROM entries
GROUP BY username
This returns this in your case:
"userB";22;"2014-01-22 12:26:06"
"userA";22;"2014-01-22 08:00:14"
However, I think what you want (in your example would be wrong) the most recent row. To do it, you need this:
SELECT username, MAX(score), MAX(modified)
FROM entries
GROUP BY username
Which returns:
"userB";22;"2014-01-22 18:49:01"
"userA";22;"2014-01-22 16:13:22"
If I have a table and data like this:
ID | Name | Group
1 Apple A
2 Boy A
3 Cat B
4 Dog C
5 Elep C
6 Fish C
and I wish to order it according to the total of Group from smallest to largest value, such as :
A - 2 records , B - 1 record , C - 3 records , so it will become:
3 Cat B
1 Apple A
2 Boy A
4 Dog C
5 Elep C
6 Fish C
I tried
$sql = "SELECT ID,Name FROM table ORDER BY COUNT(Group)";
but it just returns one result for me.
Are there any hints? Thank you.
You need to aggregate the data first, this can be done using the GROUP BY clause:
SELECT Group, COUNT(*)
FROM table
GROUP BY Group
ORDER BY COUNT(*) DESC
The DESC keyword allows you to show the highest count first, ORDER BY by default orders in ascending order which would show the lowest count first.
...none of the other answers seem to do what the asker asked.
For table named 'things' with column 'group':
SELECT
things.*, counter.count
FROM
things
LEFT JOIN (
SELECT
things.group, count(things.group) as count
FROM
things
GROUP BY
things.group
) counter ON counter.group = things.group
ORDER BY
counter.count ASC;
which gives:
id | name | group | count
---------------------------
3 | Cat | B | 1
1 | Apple | A | 2
2 | Boy | A | 2
4 | Dog | C | 3
5 | Elep | C | 3
6 | Fish | C | 3
SELECT group, COUNT(*) FROM table GROUP BY group ORDER BY group
or to order by the count
SELECT group, COUNT(*) AS count FROM table GROUP BY group ORDER BY count DESC
Try :
SELECT count(*),group FROM table GROUP BY group ORDER BY group
to order by count descending do
SELECT count(*),group FROM table GROUP BY group ORDER BY count(*) DESC
This will group the results by the group column returning the group and the count and will return the order in group order
SELECT * FROM table
group by `Group`
ORDER BY COUNT(Group)
Try using below Query:
SELECT
GROUP,
COUNT(*) AS Total_Count
FROM
TABLE
GROUP BY
GROUP
ORDER BY
Total_Count DESC
Below gives me opposite of what you have. (Notice Group column)
SELECT
*
FROM
myTable
GROUP BY
Group_value,
ID
ORDER BY
count(Group_value)
Let me know if this is fine with you...
I am trying to get what you want too...
Q. List the name of each show, and the number of different times it has been held.
List the show which has been held most often first.
event_id show_id event_name judge_id
0101 01 Dressage 01
0102 01 Jumping 02
0103 01 Led in 01
0201 02 Led in 02
0301 03 Led in 01
0401 04 Dressage 04
0501 05 Dressage 01
0502 05 Flag and Pole 02
Ans:
select event_name, count(show_id) as held_times from event
group by event_name
order by count(show_id) desc