简体   繁体   中英

SQL - how to select all rows which have value1 in column but not value2 in same column?

I have a sql table like this:

------------------------------------------
ID    | SKU      | Name        |  Type
-------------------------------------------
2     | ABC      | Pasta       |  2
3     | XYZ      | Maggi       |  5
2     | ABC      | Pasta       |  5
6     | MNO      | Macroni     |  2
3     | XYZ      | Maggi       |  0
3     | XYZ      | Maggi       |  2

I need to find rows which have type 2 but not have an entry for type 5 or 0

For example: It should result in

------------------------------------------
ID    | SKU      | Name        |  Type
-------------------------------------------
6     | MNO      | Macroni     |  2

Is it possible to result so using this one table only? Of course it is. This table has 1.4M rows and I used this query (not sure if it is correct)

SELECT e1.* FROM reportmal e1, reportmal e2 
WHERE e1.id= e2.id
AND e1.type=2 AND e2.type=5

The query never returned anything, because it is still running. Can you help?

I like to do this with having and group by :

select e.id
from reportmal e
group by e.id
having sum(e.type = 2) > 0 and
       sum(e.type in (0, 5)) = 0;

MySQL treats boolean expressions as integers in a numeric context, with "1" for true and "0" for false. Hence sum(e.type = 2) counts the number of records in each group where type = 2 . The > 0 means that at least one such row exists. The = 0 means that no such rows exist.

If you want the original rows you can join this result back to the table.

Sounds like a typical "not exists"-query:

select * from atable result
where result.type = 2 and not exists
 (select 1 from atable no50
  where no50.type in (5,0)
        and no50.sku = result.sku
 )

or:

select * from atable result
where result.type = 2 and result.sku not in
 (select sku from atable no50
  where no50.type in (5,0)
 )

Try this using group by to find the ID which has 2 and not 0 or 5 using conditional count and then using IN to get the relevant rows.

select *
from your_table
where id in (
    select
        id
    from your_table t
    group by id
    having count(case when type = 2 then 1 end) > 0
    and count(case when type in (0,5) then 1 end) = 0
);

Demo

select  *
from    reportmal e
where   e.type = 2
    and not exists 
        (
            select  null
            from    reportmal e2
            where   e2.id = e.id
                and e2.type in (0,5)
        ) 

As for the performance issue -
The minimum you need is an index on reportmal (id).
Index on reportmal (id,type) might be better.

I think you should use this:

SELECT a.*
  FROM reportmal a
 WHERE a.type = 2
   AND NOT EXISTS (SELECT 1
                     FROM reportmal b
                    WHERE b.name = a.name
                      AND b.type IN (5,0));

It's like: "All rows with TYPE 2, and NOT EXISTS a row with same NAME and TYPE 5 or 0"

I don't know what's your parameter to define an "entry". Maybe you should add SKU on subquery (it all depends your data model).

Your query was close, but you were joining on Id which will give you a Cartesian product.

This is how I'd do it.

Select p1.*
    From pasta p1
        Left outer join pasta p2 on p1.sku=p2.sku
            And p2.type in (0,5)
        Where p2.type is null

Hope that helps you.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM