Reputation: 5077
Product ID Quantity DateAdded
1 100 4/1/14
2 200 4/2/14
3 300 4/2/14
1 80 4/3/14
3 40 4/5/14
2 5 4/6/14
1 10 4/7/14
I am using this SQL statement to display the first and last record of each item:
SELECT
ProductID, MIN(Quantity) AS Starting, MAX(Quantity) AS Ending
FROM
Records
WHERE
DateAdded BETWEEN '2014-04-01' AND '2014-04-30'
GROUP BY
ProductID, Quantity
but I am getting the same values for the Starting and Ending columns. I want to achieve something like this:
Product ID Starting Ending
1 100 10
2 200 5
3 300 40
Upvotes: 0
Views: 1123
Reputation: 10098
This works in 2012 and newer:
with x as (
select distinct productid
,first_value(quantity) over(partition by productid order by dateadded
range between unbounded preceding and current row) as starting
,last_value(quantity) over(partition by productid order by dateadded
range between current row and unbounded following) as ending
from #t
)
select productid, starting, ending
from x
Single pass through the table.
Upvotes: 0
Reputation: 1219
I did not try it on SQL Server but on MySQL this SQL is working:
SELECT
ProductID, MAX(Quantity) AS Starting, MIN(Quantity) AS Ending
FROM
Records
WHERE
DateAdded BETWEEN '2014-04-01' AND '2014-04-30'
GROUP BY
ProductID;
For DateAdded field:
SELECT
ProductID, MAX(Quantity) AS Starting, MIN(Quantity) AS Ending
FROM
Records
WHERE
convert(datetime, DateAdded) BETWEEN '2014-04-01' AND '2014-04-30'
GROUP BY
ProductID;
P.S. Missing sqlfiddle badly.. :(
Upvotes: -1
Reputation: 1270391
You are getting the same quantities because you are aggregating by quantity
in the group by
as well as product. Your version of the query, properly written would be:
SELECT ProductID, MIN(Quantity) AS Starting, MAX(Quantity) AS Ending
FROM Records
WHERE DateAdded BETWEEN '2014-04-01' AND '2014-04-30'
GROUP BY ProductID;
However, this doesn't give you the first and last values. It only gives you the minimum and maximum ones. To get those values, use row_number()
and conditional aggregation:
SELECT ProductID,
MAX(CASE WHEN seqnum_asc = 1 THEN Quantity END) as Starting,
MAX(CASE WHEN seqnum_desc = 1 THEN Quantity END) as Ending
FROM (SELECT r.*,
row_number() over (partition by product order by dateadded asc) as seqnum_asc,
row_number() over (partition by product order by dateadded desc) as seqnum_desc
FROM Records r
) r
WHERE DateAdded BETWEEN '2014-04-01' AND '2014-04-30'
GROUP BY ProductID;
If you are using SQL Server 2012, then you can also use this with FIRST_VALUE()
and LAST_VALUE()
instead of row_number()
.
Upvotes: 2
Reputation: 51504
Use the row_number()
ranking function
select starting.*, ending.ending
from
(select ProductID, quantity as starting from
(select * , ROW_NUMBER() over (partition by productid order by dateadded) rn
from yourtable
where DateAdded BETWEEN '2014-04-01' AND '2014-04-30'
) first
where rn = 1) starting
inner join
(select ProductID, quantity as ending from
(select * , ROW_NUMBER() over (partition by productid order by dateadded desc) rn
from yourtable
where DateAdded BETWEEN '2014-04-01' AND '2014-04-30'
) last
where rn = 1) ending
on starting.productid=ending.productid
The first subquery gets the first entry for the time period, the second gets the last entry
Upvotes: 3
Reputation: 8865
DECLARE @test Table
(ID INT, Name INT)
INSERT INTO @test
VALUES
(1, 100),
(2, 200),
(3, 300 ),
(1, 5),
(2, 10),
(3, 15);
select ID,MIN(name),MAX(name) from @test
group by ID
Upvotes: 0
Reputation: 19903
Change your query to this
SELECT
ProductID, MIN(Quantity) AS Starting, MAX(Quantity) AS Ending
FROM
Records
WHERE
DateAdded BETWEEN '2014-04-01' AND '2014-04-30'
GROUP BY
ProductID
you don't need to make a group for quantity
Upvotes: 0