How to max(date) and use the in feature in sql ser

2019-05-27 12:24发布

问题:

I have a table such as this

id   color  shade   date
---  ----   -----   -----
1    red    dark    01/01/1990
2    red    light   09/16/2013
3    green  light   08/15/2010
4    green  dark    09/18/2012
5    maroon dark    08/20/2013
6    white  dark    08/31/2013
7    white  light   08/30/2012
8    purple light   08/20/2010

I wanted entries for each color with the latest date. So I tried doing:

select id, color, shade, max(date) from mytable;

This didn't work and gave me error:

is invalid in the select list because it is not contained in either an aggregate 
function or the GROUP BY clause.

Alright, so I added it in the Group By as suggested by the error

select id, color, shade, max(date) from mutable
Group by id, color, shade

This gave me the desired results.

Question

Now, I wanted the same query as above repeated only for certain colors. For example I only wanted to see red and green ones.

So I did:

select id, color, shade, max(date) from mutable
Where color in ('red', 'green')
Group by id, color, shade;

However, this does not give me the correct number of results because I guess they are being grouped by shade.

What is the best way to fetch my desired results? Basically I want max date out of the two instances of same thing and further out of the table only want certain colors.

回答1:

In standard SQL any of the following queries solve the issue:

Option 1

SELECT t1.* FROM t t1
LEFT JOIN t t2
ON t1.color = t2.color AND t1.shade = t2.shade AND t1.date < t2.date
WHERE t2.date IS NULL

Option 2

SELECT t1.* FROM t t1
JOIN (
  SELECT color, shade, max(date) date FROM t
  GROUP BY color, shade
) t2
ON t1.color = t2.color AND t1.shade = t2.shade AND t1.date = t2.date

In your example data, all the result should be returned, so it doesn't make much sense to operate on it. I've slightly changed it into this:

| ID | COLOR | SHADE |       DATE |
|----|-------|-------|------------|
|  1 |   red |  dark | 1990-01-01 |
|  2 |   red |  dark | 2013-09-16 |
|  3 | green | light | 2010-08-15 |
|  4 | green |  dark | 2012-09-18 |
|  5 | green |  dark | 2013-08-20 |
|  6 | white |  dark | 2013-08-31 |
|  7 | white | light | 2012-08-30 |
|  8 | white | light | 2010-08-20 |

The output of the queries would be:

| ID | COLOR | SHADE |       DATE |
|----|-------|-------|------------|
|  2 |   red |  dark | 2013-09-16 |
|  3 | green | light | 2010-08-15 |
|  5 | green |  dark | 2013-08-20 |
|  6 | white |  dark | 2013-08-31 |
|  7 | white | light | 2012-08-30 |

Make sure you apply the appropriate orderings.

Fiddle here.



回答2:

Try this

SELECT t1.* FROM t t1
JOIN 
(
  SELECT color, MAX([date]) [date] FROM t
  WHERE color IN ('red', 'green')
  GROUP BY color
) t2
ON t1.color = t2.color AND t1.date = t2.date
ORDER BY ID

OUTPUT

id  color   shade   date
2   red     light   2013-09-16
5   green   dark    2013-08-20

OR

SELECT id, color, shade, [date]
FROM 
(
  SELECT *,
        row_number() OVER (PARTITION BY color ORDER BY [date] DESC) AS sno
  FROM t
  WHERE color IN ('red', 'green')
) tt
WHERE sno = 1
ORDER BY ID

OUTPUT

id  color   shade   date
2   red     light   2013-09-16
5   green   dark    2013-08-20

OR

SELECT id, color, shade, [date]
FROM 
(
  SELECT *,
        MAX([date]) OVER (PARTITION BY color) AS maxdate
  FROM t
  WHERE color IN ('red', 'green')
) tt
WHERE [date] = maxdate
ORDER BY ID

OUTPUT

id  color   shade   date
2   red     light   2013-09-16
5   green   dark    2013-08-20


回答3:

select id, color, shade, max(date) over() AS m_date from mutable

OVER CLAUSE used IN analyze functions



回答4:

A simple way to think about this is by first creating a query that gives you the latest date for each colour:

select color, max([date]) as maxdate
from mytable
group by color;

Then by joining this query with a simple select query that just retrieves all rows from your original table:

select t.[id], t.color, t.shade, sq.maxdate
from mytable as t
inner join (
  select color, max([date]) as maxdate
  from mytable
  group by color
) as sq
on (t.color = sq.color);

Then, to restrict the results to only certain colours, just add on your where clause at the end of the query:

where color in ('red', 'green');


回答5:

The easiest way to do this is with window/ranking functions. Here is an example with row_number():

select id, color, shade, "date"
from (select t.*,
             row_number() over (partition by color order by "date" desc) as seqnum
      from mytable
     ) t
where seqnum = 1;