BujinRikimaru
BujinRikimaru

Reputation: 23

SQL Server 2008 How can I SELECT rows with Value by GROUP(ing) other column?

Hi guys I'm a beginner at SQL so please bear with me.. :)

My question is as follows.

I got this table:

     DateTime         ID     Year    Month   Value    Cost
-------------------|------|--------|-------|-------|--------|
 1-1-2013 00:00:01 |  1   |  2013  |   1   |  30   |   90   |
 1-1-2013 00:01:01 |  1   |  2013  |   1   |  0    |   0    |
 1-1-2013 00:02:01 |  1   |  2013  |   1   |  1    |   3    |
 1-2-2013 00:00:01 |  1   |  2013  |   2   |  2    |   6    |
 1-2-2013 00:01:01 |  1   |  2013  |   2   |  3    |   9    |
 1-2-2013 00:02:01 |  1   |  2013  |   2   |  4    |   12   |
 1-3-2013 00:00:01 |  1   |  2013  |   3   |  5    |   15   |
 1-3-2013 00:01:01 |  1   |  2013  |   3   |  6    |   18   |
 1-3-2013 00:02:01 |  1   |  2013  |   3   |  7    |   21   |

Now what I'm trying to get is this result

   Year    Month   Value    Cost
|--------|-------|-------|--------|
|  2013  |   1   |  1    |   3    |
|  2013  |   2   |  4    |   12   |
|  2013  |   3   |  7    |   21   |

As you can see I'm trying to GROUP BY the [Month] and the [Year] and to get the last [Value] for every [Month].

Now as you can understand from the result I do not try to get the MAX() value from the [Value] column but the last value for every [Month] and that is my issue..

Thanks in advance

PS
I was able to GROUP BY the [Year] and the [Month] but as I understand that when I adding the [Value] column the GROUP BY is not effecting the result, as the SQL need more spcification on the value you what the SQL to get..

Upvotes: 1

Views: 820

Answers (2)

Jacco
Jacco

Reputation: 3272

Instead of using row_number(), you can also use rank(). Using rank() might give you multiple values within the same year and month, see this post. Because of this, a group by is added.

SELECT
  [Year],
  [Month],
  [Value],
  [Cost]
FROM
(
  SELECT 
    [Year],
    [Month],
    [Value],
    [Cost],
    Rank() OVER (PARTITION BY [Year], [Month] ORDER BY [DateTime] DESC) AS [Rank]
  FROM [t1]
) AS [sub]
WHERE [Rank] = 1
GROUP BY 
  [Year],
  [Month],
  [Value],
  [Cost]
ORDER BY
  [Year] ASC,
  [Month] ASC

As stated in the comments, this might still return multiple records for a single month. Therefor the ORDER BY statement can be extended, based on the desired functionality:

Rank() OVER (PARTITION BY [Year], [Month] ORDER BY [DateTime] DESC, [Value] DESC, [Cost] ASC) AS [Rank]

Switching the order of [Value] and [Cost] or ASC <> DESC will influence the rank and because of that the result.

Upvotes: 1

Taryn
Taryn

Reputation: 247700

Since you are using SQL Server 2008, you can use row_number() to get the result:

select year, month, value, cost
from
(
  select year, month, value, cost,
    row_number() over(partition by year, month order by datetime desc) rn
  from yourtable
) src
where rn = 1

See SQL Fiddle with Demo

Or you can use a subquery to get this (note: with this version if you have more than one record with the same max datetime per month then you will return each record:

select t1.year, t1.month, t1.value, t1.cost
from yourtable t1
inner join
(
  select max(datetime) datetime
  from yourtable
  group by year, month
) t2
  on t1.datetime = t2.datetime

See SQL Fiddle with Demo

Both give the same result:

| YEAR | MONTH | VALUE | COST |
-------------------------------
| 2013 |     1 |     1 |    3 |
| 2013 |     2 |     4 |   12 |
| 2013 |     3 |     7 |   21 |

Upvotes: 0

Related Questions