MySQL Group By + Order - php

I've got a problem with grouping my rows.
Example Table
ID, GroupID, INFO, COUNTER
1, 123456, INFO, 21
2, 654321, INFO, 20
3, 123456, INFO, 30
4, 654321, INFO, 11
First of all, I'd like to display them with this:
SELECT *
FROM table
GROUP BY GroupID
ORDER BY COUNTER DESC
LIMIT 0, 60
So it should display only one of group type. It does, but the order is not good. So I think it's not getting the right number of counter paired to the GroupID.
The right displayed result would be: (the main order selector has to be the count)
ID, GroupID, INFO, COUNTER
3, 123456, INFO, 30
2, 654321, INFO, 20
How should I solve?

SELECT tablename.* FROM tablename
WHERE tablename.COUNTER =
(SELECT MAX(COUNTER) FROM tablename AS f WHERE f.GroupID = tablename.GroupID)
ORDER BY tablename.COUNTER DESC
Edited : This will get you the complete rows containing the max value of COUNTER for each GroupID, and order the final results by COUNTER desc.

Related

mysql statement to get the rank of a given row id in an ordered result set

I have a mysql table with multiple columns. The primary key of the table is the 'id' column. A row has multiple columns but the most relevant one for this question is 'Date' which is basically a timestamp. What is an efficient way to get the order (rank) of a given row id if I want to order the rows by their timestamp. The most recent timestamp is of rank 1, the second is of rank 2 and so on. I want to return the rank of a given row
Edit: I use ORDER BY to get an ordered set but I want the mysql statement to return the order of the specific item, not an ordered rows. I also don't want to parse the result set since this is very time cosnuming
Edit2: for example assume the following table
id timestamp name
1 Dec 4, 2016 Bob
2 Jan 1, 2015 Eve
3 Feb 6, 2017 Alice
Given an id, I should return the order of the item
id=1, expected output: 2
id=2, expected output: 3 (least recent)
id=3, expected output: 1 (most recent)
answer with out edit :Use row_number () over (order by ) clause and put some *dummy
select ROW_NUMBER()over(order by (select1) ) as renk ,* from table
answer after edit in question..
select ROW_NUMBER()over(order by timestamp desc ) as renk ,* from table
Hi try this in mysql
SET #rank=0;
SELECT t.rank FROM
(SELECT #rank:=#rank+1 AS rank, id
FROM `table_name`
ORDER BY timestamp DESC) t WHERE t.id=5;
selct * from table where id>1 order by id asc limit 1
if( not date ){
selct * from table where id>0 order by id asc limit 1
}

MySQL one row per user depending on maxDate or maxId

I have one table in MYSQL called enrollments with these fields: id, user, estimated_date.
The values in this case are:
id, user, estimated_date
1, 1, 2015-10-10
2, 1, 2015-10-10
3, 2, 2015-10-20
4, 2, 2015-10-10
I want to select one row per user: the one that has the max(estimated_date). But in case the estimated_date is equal has to select the one that has the max(id). In other words... a group by with ordering by estimated_date and id (in this order).
The output should be:
2, 1, 2015-10-10
3, 2, 2015-10-20
I have this code now:
SELECT * from enrollments m
INNER JOIN
(SELECT user,
max(estimated_date) AS maxdate
FROM enrollments
GROUP BY user
) x ON m.user = x.user
AND m.estimated_date = x.maxdate
Could you help me please? I've been searching a lot but I didn't find anything that fits this case... Thanks!
You don't need an INNER JOIN, just a ORDER by estimated_date DESC, id DESC is enough. Here is your query:
Select * FROM (
SELECT
DISTINCT `id`, `user`, `estimated_date`
FROM
enrollments
ORDER by estimated_date DESC, id DESC
) as X
GROUP BY user
full fiddle here: http://sqlfiddle.com/#!9/31799/3

Select count for each distinct row (mysql and php)

I am using mysql and php.
I have a table with one column. I can show unique rows by:
select distinct id from id_table
This might show
1
2
3
5
What I want to do is show the number of 1's, 2's, etc there are.
I could do
select count(id) from id_table where id = 1
But then I have to run a query for every... single... row... And with hundreds of thousands of rows, not good.
Is there a way to return an array of the counts of each distinct item
Data
1, 1, 1, 2, 3, 3, 5
Results
3, 1, 2, 1
Thanks
select id, count(id)
from table
group by id
If only want count of ids, then
select count(id)
from table
group by id
Here is a simple tutorial of group by clause
http://www.w3schools.com/sql/sql_groupby.asp

ordering mysql table for the max of two variables

hope someone can help me with this issue.
I have a table with two columns, and i want to select items from that table and order them depending on which of these two values is higher.
lets say i have columns 'x' and 'y' and i have these entries:
x ; y
1.- 10 ; 12
2.- 5 ; 10
3.- 11 ; 20
i want the response to be ordered: 3, 1, 2
i know this wont help, since it has no sence in the mysql, but is a representation of my idea
$query = (mysql_query("SELECT * FROM productos ORDER BY MAX(x, y)"));
i dont want to create a new variable in the table for this query.
Any idea? thanks a lot
You want to sort it after x or y, depending which is higher?
SELECT * FROM products ORDER BY GREATEST(x, y)
But in your case this is 3, 2, 1 because 15(y) is higher than -5(x) and also higher than the greatest in row 1. So I am a bit confused.
Supporting NULLs and correct order:
SELECT * FROM products ORDER BY GREATEST(COALESCE(x, 0), COALESCE(y, 0)) DESC
If you need other value as default than 0 just replace it.
Select
*
from
products
order by
Case when x>y then x else y end DESC
SELECT *
FROM products
ORDER BY GREATEST(x,y) DESC
, LEAST(x,y) DESC
The second part of the ordering (LEAST) is to put a row with (12,20) before a row with (10,20).
Since the two fields can have NULL:
SELECT *
FROM products
ORDER BY GREATEST( COALESCE(x,0), COALESCE(y,0) ) DESC
, LEAST( COALESCE(x,0), COALESCE(y,0) ) DESC ;

What mysql query would let me get aggregated stats, by month from this table?

I have a points system setup on my site, where every single point accumulated is logged in the points table. The structure is simple, p_userid, p_points (how many points accumulated during this action), and p_timestamp.
I wanna display top 3 point accumulating users, for each month. So essentially, it should sum the p_points table for the month, for each user id, and display the top 3 users, grouped into months. The user ids will be joined to a users table, to get actual user names.
What would be the best way to do it? I use php/mysql.
EDIT:
As a possible solution, I could create another column, and log YYYY-MM into it, and simply group it based on that, but thats more data I gotta log, for an already huge table.
EDIT 2:
Data stored as such
INSERT INTO `points` (`point_userid`, `point_points`, `point_code`, `point_date`) VALUES
(8465, 20, 3, 1237337627),
(46745, 20, 3, 1237337678),
(7435, 20, 3, 1237337733),
(46565, 20, 3, 1237337802),
(4466, 20, 3, 1237337836),
(34685, 20, 3, 1237337885),
(8544, 20, 3, 1237337908),
(6454, 20, 3, 1237337998),
(45765, 20, 3, 1237338008),
(3476, 20, 3, 1237338076);
This isn't easy in MySQL.
First you need to create a table of variables, one for storing the current group, and one for storing the current row number in the group. Initialize them both to NULL.
Then iterate group by month and select all rows ordered by score and select the current rown number and increase it. If the group changes, reset the row number to one.
Then put all this in a subselect and in the outer select, select all rows with rownumber <= 3.
You could use this query:
SELECT month, p_userid, points FROM (
SELECT
*,
(#rn := CASE WHEN month = #last_month THEN #rn + 1 ELSE 1 END) AS rn,
(#last_month := month)
FROM (
SELECT p_userid, month(p_timestamp) AS month, SUM(p_points) AS points
FROM Table1, (SELECT #last_month := NULL, #rn := 0) AS vars
GROUP BY p_userid, month(p_timestamp)
ORDER BY month, points DESC
) AS T1
) AS T2
WHERE rn <= 3
Result:
Month User Score
1 4 7
1 3 5
1 2 4
2 4 17
2 5 10
2 3 6
Test data:
CREATE TABLE Table1 (p_userid INT NOT NULL,
p_points INT NOT NULL,
p_timestamp TIMESTAMP NOT NULL);
INSERT INTO Table1 (p_userid, p_points, p_timestamp) VALUES
(1, 1, '2010-01-01'),
(1, 2, '2010-01-02'),
(1, 3, '2010-02-01'),
(2, 4, '2010-01-01'),
(3, 5, '2010-01-01'),
(3, 6, '2010-02-01'),
(4, 7, '2010-01-01'),
(4, 8, '2010-02-01'),
(4, 9, '2010-02-02'),
(5, 10, '2010-02-02');
Hm,
Too simple?
SELECT COUNT(tb1.p_points) as total_points, tb1.p_userid, tb1.p_timestamp, tb2.username
FROM tb1, tb2
WHERE tb1.p_userid = tb2.username AND p_timestamp BETWEEN 'start_of_date' AND 'end_of_month'
GROUP BY p_userid
ORDER BY total_points DESC LIMIT 3
Syntax might be a little bit out (relatively new to SQL) - wouldn't iterating through a query like this get the result you're looking for? Must admit that Mark's response makes me think this definitely is too simple but figured I'd let you see it anyway.
I'm plpgsql addicted and I don't know if something simmilar can work in MySQL, and how PHP will get results (I don't know if multiple queries will be taken as UNION) but few tests were promising.
CREATE PROCEDURE topusers(OUT query TEXT) BEGIN
DECLARE time TIMESTAMP;
SELECT MIN(CONCAT(EXTRACT(YEAR_MONTH FROM FROM_UNIXTIME(p_timestamp)), '01')) INTO time FROM t;
SET #query = '';
REPEAT
SET #query = CONCAT(#query, '(SELECT SUM(p_points) as total_points, p_userid, ', UNIX_TIMESTAMP(time), '
FROM t
WHERE p_timestamp BETWEEN ', UNIX_TIMESTAMP(time), ' AND ', UNIX_TIMESTAMP(ADDDATE(time, INTERVAL 1 MONTH)), '
GROUP BY p_userid
ORDER BY total_points DESC LIMIT 3)');
SELECT ADDDATE(time, INTERVAL 1 MONTH) INTO time;
IF time < NOW() THEN
SET #query=CONCAT(#query, ' UNION ');
END IF;
UNTIL time > NOW() END REPEAT;
SELECT #query INTO query;
END//
And query
CALL topusers(#query); PREPARE stmt1 FROM #q; EXECUTE stmt1;
and at the end
DEALLOCATE PREPARE stmt1;

Categories