Question

I have a table with below structure:

create table A_TEST
(
  order_num      int,
  product_name   varchar(50),
  product_amount int,
  product_price  int
);

Sample data :

insert into a_test (order_num , product_name , product_amount , product_price)
values (1,'APPLE',1000,2000),
       (1,'APPLE',2000,5000),
       (1,'APPLE',4000,3000),
       (2,'ORANGE',280,3000),
       (2,'APPLE',200,3000),
       (3,'BANANA',2000,3000),
       (3,'APPLE',200,3000),
       (4,'POTATO',123,3000),
       (4,'POTATO',2000,3000),
       (4,'APPLE',2000,3000),
       (5,'APPLE',360,3000),
       (5,'POTATO',2000,3000),
       (5,'TOMATO',360,3000),
       (5,'BANANA',123,3000),
       (5,'ORANGE',126,3000);

What I want is to find those order_nums that have different product_names so that no two product_name for one order_num should be the same . The desired result would be (2,3,5). I tried to solve this with Exists but it won't return the correct result.

SELECT *
FROM A_TEST A
WHERE EXISTS (SELECT *
              FROM A_TEST B
              WHERE A.order_num = B.order_num
              AND A.product_name <> B.product_name);

I know why this does not return the correct result. The reason is that if it finds at least one product_name which is different from another one, it will return it's order_num. I was wondering if you could suggest better solutions.

Thanks in advance

Was it helpful?

Solution

Classic solution:

SELECT order_num
FROM a_test
GROUP BY order_num
HAVING COUNT(DISTINCT product_name) > 1;

Custom solutions:

SELECT DISTINCT t1.order_num
FROM a_test t1
JOIN a_test t2 ON t1.order_num = t2.order_num
WHERE t1.product_name != t2.product_name;
WITH cte AS ( SELECT order_num, 
                     DENSE_RANK() OVER (PARTITION BY order_num ORDER BY product_name) dr
              FROM a_test )
SELECT DISTINCT order_num
FROM cte
WHERE dr = 2;

...

fiddle


The one that you used 'Join' , again does not return the desired result. It returns those records that have equal order_num but their product_name are different and does not return records with same order_num that their product_name s are the same . Just this – Pantea

Do you mean that you need only orders which (1) have at least 2 products, and (2) have none product twice? If so then add .. AND COUNT(DISTINCT product_name) = COUNT(product_name) to the first query.

SELECT order_num
FROM a_test
GROUP BY order_num
HAVING COUNT(DISTINCT product_name) > 1
AND COUNT(DISTINCT product_name) = COUNT(product_name);

fiddle

OTHER TIPS

You'll be happy to know that what you're trying to do is perfectly achievable using regular ANSI SQL. My first thought while reading your question was to use GROUP BY. It's ideal for situations like yours where you want to apply an aggregate function (like COUNT) to a specific field - in your case, the order_num.

Here's what you get when you apply GROUP BY to the order_num, shown in my Navicat database development and admin client:

Group By query

Next, I added a HAVING clause that filters rows to those whose that have different product_names:

Group By query with COUNT DISTINCT

That's almost right, but order_num is also present, because it does have two different product_names. However, it also has a duplicate. To remove that, we can compare the COUNT DISTINCT with a straight COUNT as follows.

Group By query with both COUNT and COUNT DISTINCT

One thing that I am unclear on, is whether or not order_nums with only one product_name should be included or not. To test that case, I added an order with a single product (KIWI):

A_TEST table with single product order

If you were interested in orders with a single product, you would just need to add the line:

HAVING COUNT(product_name) = 1

Here is the modified query, along with its results:

Modified query to include orders with a single product

Here is the final SELECT statement:

SELECT order_num,
       COUNT(DISTINCT product_name)
FROM a_test
GROUP BY order_num
HAVING COUNT(product_name) = 1
OR (COUNT(DISTINCT product_name) > 1
    AND COUNT(DISTINCT product_name) = COUNT(product_name));

Rob

I think I found a better solution.Look,for those order_num s that their product_name are different from each other this equation is always true COUNT(DISTINCT product_name) = COUNT(product_name). So I think this query is better :

SELECT order_num
FROM
(
SELECT order_num,
       COUNT(DISTINCT product_name) P_DISTINCT_AMT,
       COUNT(product_name) P_AMT
FROM A_TEST
GROUP BY order_num ) TT
WHERE TT.P_DISTINCT_AMT = TT.P_AMT
Licensed under: CC-BY-SA with attribution
Not affiliated with dba.stackexchange
scroll top