I’m looking for a fast and easy SQL Query to get records year by year, month by month and day by day.
My database example:
ID - DATE - CatID - VALUE
1 - 2013-08-06 - 32 - 243
2 - 2013-08-16 - 2 - 45
3 - 2013-08-21 - 2 - 1
4 - 2013-08-05 - 32 - 450
5 - 2013-08-05 - 32 - 449
6 - 2013-08-05 - 32 - 11
7 - 2013-08-01 - 2 - 221
8 - 2013-08-02 - 32 - 0
9 - 2013-08-02 - 32 - 0
10 - 2013-08-02 - 32 - 987
..
I have over 2 millions records on this table.
First:
I would like to get CatID = 32 and single/higher record of the day.
Result:
1 - 2013-08-06 - 32 - 243
4 - 2013-08-05 - 32 - 450
10 - 2013-08-02 - 32 - 987
Second:
I would like to get as same but by MONTH.
How can I do it with SQL SERVER. Currently Sql Server 2012.
Also using C# 5 and if you want to use, EF 6.
Down voters, this question became “popular question”. Now please explain why down voted?
Advertisement
Answer
The below assumes that you want more than just the max value for each date/month, but also want to know the id
of that row, etc, etc.
For daily…
WITH
sorted AS
(
SELECT
*,
ROW_NUMBER() OVER (PARTITION BY CatID,
Date
ORDER BY Value DESC) AS ordinal_cat_date
FROM
yourTable
)
SELECT
*
FROM
sorted
WHERE
ordinal_cat_date = 1
AND catID = 32
For monthly…
WITH
sorted AS
(
SELECT
*,
ROW_NUMBER() OVER (PARTITION BY CatID,
DATEADD(MONTH, DATEDIFF(MONTH, 0, Date), 0)
ORDER BY Value DESC) AS ordinal_cat_month
FROM
yourTable
)
SELECT
*
FROM
sorted
WHERE
ordinal_cat_month = 1
AND catID = 32
In both cases the ROW_NUMBER()
function creates a sequence of numbers (1,2,3,4,etc)
for each PARTITION
of catID, date
, in descending order of value
. Whichever row has a value of 1
is the row with the highest value in that partition.
The formula DATEADD(MONTH, DATEDIFF(MONTH, 0, Date), 0)
just rounds the Date
down to the first day of the month, thereby creating partitions for whole months.
Some other options that bring through multiple rows per day/month if those rows all share the same highest value…
SELECT -- Daily Version
*
FROM
yourTable
WHERE
NOT EXISTS (SELECT *
FROM yourTable AS lookup
WHERE lookup.CatID = yourTable.CatID
AND lookup.Value > yourTable.Value
AND lookup.Date = yourTable.Date
)
AND CatID = 32
SELECT -- Monthly Version
*
FROM
yourTable
WHERE
NOT EXISTS (SELECT *
FROM yourTable AS lookup
WHERE lookup.CatID = yourTable.CatID
AND lookup.Value > yourTable.Value
AND lookup.Date >= DATEADD(MONTH, DATEDIFF(MONTH, 0, yourTable.Date), 0)
AND lookup.Date < DATEADD(MONTH, 1+DATEDIFF(MONTH, 0, yourTable.Date), 0)
)
AND CatID = 32
Or possibly…
SELECT -- Daily Version
*
FROM
yourTable
INNER JOIN
(
SELECT
Date,
CatID,
MAX(Value) AS max_value
FROM
yourTable
GROUP BY
CatID,
Date
)
AS lookup
ON yourTable.Date = lookup.Date
AND yourTable.CatID = lookup.CatID
AND yourTable.Value = lookup.max_value
WHERE
yourTable.CatID = 32
SELECT -- Monthly Version
*
FROM
yourTable
INNER JOIN
(
SELECT
CatID,
DATEADD(MONTH, DATEDIFF(MONTH, 0, yourTable.Date), 0) AS month_start,
MAX(Value) AS max_value
FROM
yourTable
GROUP BY
CatID,
DATEADD(MONTH, DATEDIFF(MONTH, 0, yourTable.Date), 0)
)
AS lookup
ON yourTable.Date >= lookup.month_start
AND yourTable.Date < DATEADD(MONTH, 1, lookup.month_start)
AND yourTable.CatID = lookup.CatID
AND yourTable.Value = lookup.max_value
WHERE
yourTable.CatID = 32