GROUP BY max in mysql - mysql

Let's say I have the following two entries:
`id` | `timestamp` | `content` | `reference`
1 | 2012-01-01 | NEWER | 1
2 | 2013-01-01 | NEWEST | 1
3 | 2011-01-01 | OLD | 2
I need the following result from my query:
`id` | `timestamp` | `content` | `reference`
2 | 2013-01-01 | NEWEST | 1
3 | 2011-01-01 | OLD | 2
Here's what I have so far, but it is incorrect:
SELECT * FROM table GROUP BY reference
What would be the correct query here?
I am looking to get the newest piece of content per reference id. In the example above, there are two reference id's (1 & 2), and I want to get the most recent entry for each.

SELECT *
FROM (SELECT * FROM table ORDER BY timestamp desc) as sub
GROUP BY reference
If you wish to expand the query, put limiting logic into the subquery like so for better performance:
SELECT *
FROM (SELECT *
FROM table
WHERE 1=1 and 2=2
ORDER BY timestamp desc
) as sub
GROUP BY reference

I take it you want the newest of each reference? Something like this:
SELECT * FROM my_table
WHERE id IN (
SELECT id FROM my_table ORDER BY timestamp DESC GROUP BY reference LIMIT 1
);

select * from table where reference_id in
(select max(id) from table group by reference)

Related

How to select rows that has distinct value in one field and sorted by another field in MySQL?

I have a table like this:
-----------------------------
id | uid | year | other | many | fields
-----------------------------
1 | 1 | 2010 | blabla ...
2 | 2 | 1999 | blablabla ...
3 | 3 | 2011 | bla ...
4 | 1 | 2006 | blablablabla ...
...
-----------------------------
What I want is to select all fields in all records that
has distinct uid and only returns the last record (i.e., has the highest id)
the results are sorted by year
An example of returned records like:
-----------------------------
id | uid | year | other | many | fields
-----------------------------
2 | 2 | 1999 | blablabla ...
4 | 1 | 2006 | blablablabla ...
3 | 3 | 2011 | bla ...
-----------------------------
It looks like similar to question How to use DISTINCT and ORDER BY in same SELECT statement? but I couldn't get it work.
I tried SELECT * FROM table GROUP BY uid ORDER BY MAX(id) DESC, MAX(year), but it seems neither sorting id nor year.
update:
Thanks for all solutions, here is the new problem: I'm actually developing plugin in Discuz, and it doesn't allow sub queries for security reason, is there any way to use only one select? Or any workaround in Discuz plugin development? Thanks again.
you can try this one
select distinct * from test where id IN (select MAx(id) id from test GROUP BY uid) order by year
test=>table name;
it will give out put as
To my knowledge, I can give you two approaches,
(1) Mysql specific
SELECT * FROM (SELECT * FROM `table_name` ORDER BY `id` DESC) tbl
GROUP BY `uid` ORDER BY `year`
Note: In Mysql, we don't have to apply GROUP BY to every column in order to get its non-aggregate value and instead, only the first row is returned.
(2) For any RDBMS
SELECT * FROM table_name
WHERE id IN (
SELECT Max(id) FROM table_name
GROUP BY uid
)
ORDER BY year
OR
SELECT tbl1.id, tbl1.uid, tbl1.year, tbl1.other
FROM table_name tbl1
INNER JOIN (
SELECT Max(id) id FROM table_name
GROUP BY uid
) tbl2
ON tbl1.id = tbl2.id
ORDER BY tbl1.year
All of the above statements will yield the same result as below:
----------------------------
| id | uid | year | other |
-----+-----+------+------------
| 2 | 2 | 1999 | blablabla ...
| 4 | 1 | 2006 | blablablabla ...
| 3 | 3 | 2011 | bla ...
-----------------------------
The following query might do the job done.
SELECT
your_table.id,
your_table.uid,
your_table.year,
your_table.other
FROM your_table
INNER JOIN
(
SELECT
uid,
MAx(id) max_id
FROM your_table
GROUP BY uid
) t
ON your_table.id = t.max_id AND your_table.uid = t.uid
ORDER BY your_table.id, your_table.year;
The above query will return the records corresponding to maximum id under same uid and sorts the records in ascending order of id and year.
SQL FIDDLE is not working
TEST DATA:
DROP TABLE IF EXISTS `your_table`;
CREATE TABLE `your_table` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`uid` int(50) NOT NULL,
`year` int(11) NOT NULL,
`other` varchar(100) CHARACTER SET utf8 NOT NULL,
PRIMARY KEY (`id`)
);
INSERT INTO `your_table` VALUES ('1', '1', '2010', 'blabla ...');
INSERT INTO `your_table` VALUES ('2', '2', '1999', 'blablabla...');
INSERT INTO `your_table` VALUES ('3', '3', '2011', 'bla ...');
INSERT INTO `your_table` VALUES ('4', '1', '2006', 'blablablabla....');
Output:
Running the above query on these test data you will get the following output.
id uid year other
2 2 1999 blablabla...
3 3 2011 bla ...
4 1 2006 blablablabla....

How to deduplicate mysql rows but keep max view

I have MySQL rows like this
id | title | desc | view
1 | i'm a title | i'm a desc | 0
2 | i'm a title | i'm a desc | 0
3 | i'm a title | i'm a desc | 5
4 | i'm a title | i'm a desc | 0
5 | i'm a title | i'm a desc | 0
6 | i'm a title | i'm a desc | 3
8 | i'm a title | i'm a desc | 0
And i would like to keep only
3 | i'm a title | i'm a desc | 5
because this record as the max view and others are duplicates
If your data is not too big, you can use delete like this:
delete t from yourtable t join
(select title, `desc`, max(view) as maxview
from yourtable t
group by title, `desc`
) tt
on t.title = tt.title and
t.`desc` = tt.`desc` and
t.view < tt.maxview;
Note: if there are multiple rows with the same maximum number of views, this will keep all of them. Also, desc is a lousy name for a column because it is a SQL (and MySQL) reserved word.
EDIT:
If you have a large amount of data, often it is faster to do the truncate/re-insert approach:
create table temp_t as
select t.*
from yourtable t join
(select title, `desc`, max(view) as maxview
from yourtable t
group by title, `desc`
) tt
on t.title = tt.title and
t.`desc` = tt.`desc` and
t.view = tt.maxview;
truncate table yourtable;
insert into yourtable
select *
from temp_t;
I could not understand what the specific question is. The possible solutions are followed...
1) Use UPDATE instead of INSERT statement in mysql. Just write UPDATE your_table_name SET view=view+1
2) or you can run a cron job if using php to delete duplicate rows having lower value
3) If INSERT is necessary then you should do ON DUPLICATE KEY UPDATE. Refer to the documentation * http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html

Passing the results of a Mysql query to a subquery on the same table

CREATE TABLE test (
id INT(12),
time VARCHAR(16),
group INT(2),
taken TINYINT(1),
RID int(11) NOT NULL auto_increment,
primary KEY (RID));
id | time | group | taken
---------------------------
1 | 13.00| 1 | 1
---------------------------
2 | 13.00| 2 | 0
---------------------------
3 | 14.00| 2 | 0
---------------------------
4 | 15.00| 2 | 0
---------------------------
5 | 12.00| 3 | 0
Having a table structure and sample data as above, I want to get the smallest "group" number which has not been "taken" (taken=0)
I have come with two queries :
SELECT * From `test`
WHERE taken=0
and
SELECT * FROM `test`
WHERE `group` = ( SELECT MIN(`group`) FROM `test` )
Can someone show me how to combine the two queries so that I can pass the results of the first query to the second query to get as below.
id | time | group | taken
---------------------------
2 | 13.00| 2 | 0
---------------------------
3 | 14.00| 2 | 0
---------------------------
4 | 15.00| 2 | 0
---------------------------
You can use the result of the first query in the second query as follows:
SELECT *
FROM TEST
WHERE `group` = (SELECT MIN(`group`)
FROM `test`
WHERE taken = 0)
Which gives you the desired result according to this SQLFiddle
Use the sub query to get the lowest group for taken of 0. Join your main table to the results of the sub query.
Something like this:-
SELECT a.*
From `test` a
INNER JOIN
(
SELECT MIN(`group`) AS min_group
FROM `test`
WHERE taken=0
) b
ON a.taken = b.taken
AND a.`group` = b.min_group
try this:
SELECT min(`group`) FROM (
SELECT * FROM test
WHERE taken = 0)
AS t;

Get N per group MYSQL

IT IS NOT THE SAME QUESTION AS : Using LIMIT within GROUP BY to get N results per group?
but i admit it is similar.
I need to select the first 2 rows per person.
the rows are ordered by Year received
Problem : there is a possibility than 2 data were entered the same month (Date is entered YYYY-MM)
The query I came with (following the referred question) is stuck in an BIG loop.
SELECT *
FROM `table_data` as b
WHERE (
SELECT count(*) FROM `table_data` as a
WHERE a.Nom = b.Nom and a.year < b.year
) <= 2;
Sample Data :
A | year | Nom
---------------------
b | 2011-01 | Tim
---------------------
d | 2011-01 | Tim
---------------------
s | 2011-01 | Tim
---------------------
a | 2011-03 | Luc
---------------------
g | 2011-01 | Luc
---------------------
s | 2011-01 | Luc
Should export :
A | year | Nom
---------------------
b | 2011-01 | Tim
---------------------
d | 2011-01 | Tim
---------------------
a | 2011-03 | Luc
---------------------
g | 2011-01 | Luc
(
-- First get a set of results as if you only wanted the latest entry for each
-- name - a simple GROUP BY from a derived table with an ORDER BY
SELECT *
FROM (
SELECT *
FROM `table_data`
ORDER BY `year` DESC
) `a`
GROUP BY `Nom`
)
UNION
(
-- Next union it with the set of result you get if you apply the same criteria
-- and additionally specify that you do not want any of the rows found by the
-- first operation
SELECT *
FROM (
SELECT *
FROM `table_data`
WHERE `id` NOT IN (
SELECT `id`
FROM (
SELECT *
FROM `table_data`
ORDER BY `year` DESC
) `a`
GROUP BY `Nom`
)
ORDER BY `year` DESC
) `b`
GROUP BY `Nom`
)
-- Optionally apply ordering to the final results
ORDER BY `Nom` DESC, `year` DESC
I feel sure there is a shorter way of doing it but right now I can't for the life of me work out what it is. That does work, though - assuming you have a primary key (which you should) and that it is called id.

Sort data before using GROUP BY?

I have read that grouping happens before ordering, is there any way that I can order first before grouping without having to wrap my whole query around another query just to do this?
Let's say I have this data:
id | user_id | date_recorded
1 | 1 | 2011-11-07
2 | 1 | 2011-11-05
3 | 1 | 2011-11-06
4 | 2 | 2011-11-03
5 | 2 | 2011-11-06
Normally, I'd have to do this query in order to get what I want:
SELECT
*
FROM (
SELECT * FROM table ORDER BY date_recorded DESC
) t1
GROUP BY t1.user_id
But I'm wondering if there's a better solution.
Your question is somewhat unclear but I have a suspicion what you really want is not any GROUP aggregates at all, but rather ordering by date first, then user ID:
SELECT
id,
user_id,
date_recorded
FROM tbl
ORDER BY date_recorded DESC, user_id ASC
Here would be the result. Note reordering by date_recorded from your original example
id | user_id | date_recorded
1 | 1 | 2011-11-07
3 | 1 | 2011-11-06
2 | 1 | 2011-11-05
5 | 2 | 2011-11-06
4 | 2 | 2011-11-03
Update
To retrieve the full latest record per user_id, a JOIN is needed. The subquery (mx) locates the latest date_recorded per user_id, and that result is joined to the full table to retrieve the remaining columns.
SELECT
mx.user_id,
mx.maxdate,
t.id
FROM (
SELECT
user_id,
MAX(date_recorded) AS maxdate
FROM tbl
GROUP BY user_id
) mx JOIN tbl t ON mx.user_id = t.user_id AND mx.date_recorded = t.date_recorded
Iam just using the technique
"Using order clause before group by inserting it in group_concat clause"
SELECT SUBSTRING_INDEX(group_concat(cast(id as char)
ORDER BY date_recorded desc),',',1),
user_id,
SUBSTRING_INDEX(group_concat(cast(`date_recorded` as char)
ORDER BY `date_recorded` desc),',',1)
FROM data
GROUP BY user_id