Reputation: 55
I am trying to create a select statement so that it does a specific distinct on one column. I am trying to make it so that there is not multiple fruits within each id. If there is multiple fruits under an id, I would like use only 1 approved fruit, over the rotten fruit. If there is only 1 fruit under that id, use it.
SELECT id, fruit, fruitweight, status
FROM myfruits
Raw data from current select
id | fruit | fruitweight | status
1 | apple | .2 | approved
1 | apple | .8 | approved
1 | apple | .1 | rotten
1 | orange | .5 | approved
2 | grape | .1 | rotten
2 | orange | .7 | approved
2 | orange | .5 | approved
How it should be formatted after constraint
id | fruit | fruitweight | status
1 | apple | .2 | approved
1 | orange | .5 | approved
2 | grape | .1 | rotten
2 | orange | .7 | approved
I can do something along the lines of select distinct id,fruit,fruitweight,status from myfruits
,
but that will only take out the duplicates if all columns are the same.
Upvotes: 3
Views: 86
Reputation: 82010
Another option is using the WITH TIES clause.
Example
Select top 1 with ties *
From YourTable
Order By Row_Number() over (Partition By id,fruit order by status,fruitweight)
Upvotes: 3
Reputation: 438
A shorter version of scsimon's solution without aggregates. If you have SQL Server < 2012, you'll have to use case instead of iif.
select
id
,fruit
,fruitweight
,status
from
(
select
id
,fruit
,fruitweight
,status
,rownum = row_number() over(partition by id, fruit order by iif(status = 'approved', 0, 1), fruitweight desc)
from myfruits
) x
where rownum = 1
EDIT: I started writing before scsimon edited his post to included a version without aggregates...
Upvotes: 1
Reputation: 25152
CTE with aggregate and row_number.
declare @YourTable table (id int, fruit varchar(64), fruitweight decimal(2,1),status varchar(64))
insert into @YourTable
values
(1,'apple',0.2,'approved'),
(1,'apple',0.8,'approved'),
(1,'apple',0.1,'rotten'),
(1,'orange',0.5,'approved'),
(2,'grape',0.1,'rotten'),
(2,'orange',0.7,'approved'),
(2,'orange',0.5,'approved')
;with cte as(
select
id
,fruit
,fruitweight = min(fruitweight)
,[status]
,RN = row_number() over (partition by id, fruit order by case when status = 'approved' then 1 else 2 end)
from
@YourTable
group by
id,fruit,status)
select
id
,fruit
,fruitweight
,status
from
cte
where RN = 1
Another method, without the aggregate... assuming you want the first fruightweight
;with cte as(
select
id
,fruit
,fruitweight
,[status]
,RN = row_number() over (partition by id, fruit order by case when status = 'approved' then 1 else 2 end, fruitweight)
from
@YourTable)
select
id
,fruit
,fruitweight
,status
from
cte
where RN = 1
Upvotes: 4