Reputation: 14741
I have this sql table and rows defined in SQL Fiddle
In SUPPLIER_DETAILS table there is a field called IS_PAYABLE which will have values either null or 'Y'.
If IS_PAYABLE='Y'
, there could be one or more records for each PRODUCT_REG with different PRODUCT_NO.
E.g. PRODUCT_REG = 'HP_C20'
has two records with IS_PAYABLE='Y'
.
HP_C20 FR-A GB-A128 Y
HP_C20 FR-A GB-A098 Y
What I would like to have is if IS_PAYABLE='Y'
and if there are multiple records for one PRODUCT_REG, then I would want only either one of the record and I want all the records with IS_PAYABLE is null
.
How can I achieve this? If I did not make my requirement understandable, I will explain further.
Any help is highly appreciable.
Thanks
Upvotes: 5
Views: 4721
Reputation: 27251
In this situation row_number()
analytical function is going to be in handy.
select product_reg
, product_supplier_code
, product_no
, is_payable
from (select t.*
, row_number() over (partition by product_reg order by product_no) m
from SUPPLIER_DETAILS t
)
where m = 1
or is_payable is null
order by product_reg
In addition
Seems to be a duplicate. To distinguish the answer a little bit here is another approach you can use to get the desired result
select product_reg
, max(PRODUCT_SUPPLIER_CODE) KEEP (DENSE_RANK FIRST ORDER BY product_reg) PRODUCT_SUPPLIER_CODE
, max(PRODUCT_NO) KEEP (DENSE_RANK FIRST ORDER BY product_reg) PRODUCT_NO
, max(IS_PAYABLE) KEEP (DENSE_RANK FIRST ORDER BY product_reg) IS_PAYABLE
from SUPPLIER_DETAILS t
group by product_reg
order by product_reg
Upvotes: 3
Reputation: 247850
You can use UNION ALL
for this, but when returning the records where IS_PAYABLE = 'Y'
use an aggregate to always return the MAX()
or MIN()
value
select PRODUCT_REG, PRODUCT_SUPPLIER_CODE, max(PRODUCT_NO) PRODUCT_NO, IS_PAYABLE
from SUPPLIER_DETAILS
where IS_PAYABLE = 'Y'
group by PRODUCT_REG, PRODUCT_SUPPLIER_CODE, IS_PAYABLE
union all
select PRODUCT_REG, PRODUCT_SUPPLIER_CODE, PRODUCT_NO, IS_PAYABLE
from SUPPLIER_DETAILS
where IS_PAYABLE is null
order by PRODUCT_REG
Upvotes: 2
Reputation: 17643
select * from
(select a.*,
row_number() over (partition by product_reg order by product_no) as rnk
from SUPPLIER_DETAILS a
order by PRODUCT_REG)
where is_payable is null or rnk = 1;
In inner query I've ranked the products with the same product_reg.
In the outer query i've got only one product per product_reg(the first ranked) and all non payable products.
Upvotes: 5
Reputation: 12774
Try this:
SELECT s.*
FROM supplier_details s
WHERE NOT EXISTS(SELECT s1.*
FROM supplier_details s1
WHERE s.is_payable = 'Y'
AND s1.is_payable = 'Y'
AND s.product_reg = s1.product_reg
AND s.product_no < s1.product_no)
UNION
SELECT *
FROM supplier_details
WHERE is_payable IS NULL
http://sqlfiddle.com/#!4/25c52/2/0
EDIT: below code should also work(union is redundant)
SELECT s.*
FROM supplier_details s
WHERE NOT EXISTS(SELECT s1.*
FROM supplier_details s1
WHERE s.is_payable = 'Y'
AND s1.is_payable = 'Y'
AND s.product_reg = s1.product_reg
AND s.product_no < s1.product_no)
http://sqlfiddle.com/#!4/5e69b/1/0
Upvotes: 3