Home > Net >  Filter SQL result by condition to recieve only one row per customer
Filter SQL result by condition to recieve only one row per customer

Time:07-19

I want to show you my problem by this simple example.

I already have this SQL result of customers buying either rice or melon. If a customer have entries for both products, I only want to print out the data row for melon.

So this must turn into...

CustomerId Name Product Price
1234565 Zimmer Melon 5,00
1234565 Zimmer Rice 2,00
5634525 Sinclair Rice 2,00
6905455 West Rice 2,00
4433356 Poleo Melon 5,00
4433356 Poleo Rice 2,00

THIS...

CustomerId Name Product Price
1234565 Zimmer Melon 5,00
5634525 Sinclair Rice 2,00
6905455 West Rice 2,00
4433356 Poleo Melon 5,00

I already tried a query something like this.

SELECT 
CustomerId
Name
MIN(Product)
MIN(Price)

FROM LIST
GROUP BY CustomerId,Name
HAVING Product = 'Melon'

I am aware that this will never work, because I also want to see the rice entries, if they didnt bought any melons. How can I filter this list. Maybe with a case condition inside the having?

Thank you in advance.

CodePudding user response:

One way of thinking about it is you have a preference order to these items, so we can rank them and return only the first, if we have ranking window functions available to us:

WITH customers AS (
  SELECT 
    CustomerId,
    name,
    product,
    price,
    RANK() OVER (PARTITION BY CustomerId) ORDER BY (
        CASE WHEN Product = 'Melon' THEN 1 
             WHEN Product = 'Rice' THEN 2
        ...
        END
    ) AS product_rank
  FROM LIST
  GROUP BY CustomerId,Name
)
SELECT 
  CustomerId,
  name,
  product,
  price 
FROM customers
WHERE product_rank = 1;

Hope that helps.

CodePudding user response:

Row_number the rows as needed and take the first one. 'Melon' < 'Rice' so just order by Product . I'm using a handy top(1) with ties of Sql Server

select top(1) with ties
    CustomerId,
    Name,
    Product,
    Price
from LIST
order by row_number() over(partition by CustomerId order by Product)

CodePudding user response:

Here's a working query. Not the most optimal one but i guess your data is not big so it'll do the job. Test1 is your quoted table. I wrote it for mysql but it is very simple and should work on other types of dbs as well :

select * from
(select m.*, n.num from
(select customerId, name, product, min(price) from test1
group by customerId, name, product) m
left join
    (select customerId, count(1) num from test1
group by customerId) n on m.customerId=n.customerId) sq
where ((num=2 and product='Melon') OR num=1)

NB! I'm not using window functions since there are environments where they don't work (mysql<8 etc.). Also the alphabetical order works in the example but may not do the job with the actual data.

  • Related