Home > Software engineering >  How to write sql query with minus operator to return rows with missing corresponding values?
How to write sql query with minus operator to return rows with missing corresponding values?

Time:12-06

I have transaction table with columns transaction_id, transaction_category and transaction_quantity. Please view the sample data below

transaction_id transaction_category transaction_quantity
112 sale 1000
112 internal 1000
113 sale 1000
114 sale 1000
114 internal 1000
115 sale 1000
115 external 1000
116 sale 1000
116 internal 1000

In the given table, notice transaction_id 112 has both 'sale' and corresponding row with same transaction_id and 'internal' category. It is the same with transaction_id 114. But the third row with transaction_id 113 does not have another row with 'internal' category and transaction_id 115 also doesn't have a corresponding row with 'internal' category (it has external).

I need to get the list of all transactions that have transaction_category of 'sale' but does not have a corresponding transaction_category of 'internal'. So it should return rows with transaction_id of 113 and 115 in the above case. I was attempting to do this with the minus operator but have been hitting a brick wall attempting to do this.

EDIT: The table is about 5000 rows and none of the columns are indexed. Also, there are other categories too. I will update my table.

CodePudding user response:

You may try with conditional aggregation as the following:

select transaction_id
from table_name
group by transaction_id
having count(case when transaction_category='sale' then 1 end) > 0 and 
       count(case when transaction_category='internal' then 1 end) = 0

See a demo.

CodePudding user response:

SELECT T.TRANSACTION_ID
FROM TRANSACTIONS AS T
WHERE T.transaction_category='SALE'
   EXCEPT --MINUS
SELECT T.TRANSACTION_ID
FROM TRANSACTIONS AS T
WHERE T.transaction_category='INTERNAL'

May be this one

CodePudding user response:

Solution for MySQL 8.0.31, which now supports EXCEPT.

select distinct transaction_id from transaction where transaction_category = 'sale'
except
select transaction_id from transaction where transaction_category = 'internal';

MINUS is a synonym invented by Oracle and supported for compatibility in some other SQL implementations (but not MySQL).

I put the distinct in that query because it's not clear from your description if there can be only one row per category for a given transaction_id.

See also:

CodePudding user response:

Like already mentioned in other answers, EXCEPT is absolutely fine. Another good option is EXISTS:

SELECT 
transaction_id
FROM transactions t1
WHERE transaction_category = 'sale'
AND NOT EXISTS 
  (SELECT 1 FROM transactions t2 
    WHERE t1.transaction_id = t2.transaction_id 
    AND t2.transaction_category = 'internal'); 

I guess it should be clear we will add a DISTINCT if we only want to get every transaction id once.

  • Related