简体   繁体   中英

Select Records With Only One SPECIFIC Value In A Column Where Multiple Are Possible using Set Operations

Hi I am really struggling with this particular question when practicing some SQL queries on a made up dataset.

Given the following tables:

  • Movie(MovieID,Title,ProducerName)
  • DVD(MovieID,StoreID)
  • Store(StoreID,StoreName)

I am not sure how to retrieve the names of stores that only have movies from the producer "BBC" (ProducerName = BBC). I want to try use subqueries and set operations instread of joins.

I have this mostly by guesswork as I can't test the query anywhere but any help would be very much appreciated. Would there be a better way to do this without using a join at all?

select distinct(StoreName)
from STORE
where not exists (
(select distinct(Title)
from MOVIE JOIN DVDs
where DVD.StoreID == STORE.StoreID)
except
(select distinct(Title)
from MOVIE 
where producerName = ‘BBC’))

I would use not exists as follows:

select s.*
from store s
where not exists (
    select 1 
    from dvd d
    inner join movie m on m.movieID = d.movieID
    where m.producerName <> 'BBC' and d.storeID = s.storeID
)

This selects the stores that have no movie from a producer other than BBC. You can be more specific by adding another exists condition:

select s.*
from store s
where 
    exists (
        select 1 
        from dvd d
        inner join movie m on m.movieID = d.movieID
        where m.producerName = 'BBC' and d.storeID = s.storeID
    )
    and not exists (
        select 1 
        from dvd d
        inner join movie m on m.movieID = d.movieID
        where m.producerName <> 'BBC' and d.storeID = s.storeID
    )

Another option is aggregation:

select s.storeID, s.storeName
from store s
inner join dvd d on d.storeID = s.storeID
inner join movie m on m.movieID = d.movieID
group by s.storeID, s.storeName
having bool_and(m.producerName = 'BBC')

If you don't want to use any join s, you can do:

select s.*
from store s
where not exists (select 1
                  from (select dvd.*,
                               (select m.ProducerName
                                from movie m
                                where m.movieId = dvd.movieId
                               ) as ProducerName
                        from dvd
                       ) dvd
                  where dvd.ProducerName <> 'BBC' and
                        dvd.storeId = s.storeId
                 );

You can also next an exists clause:

select s.*
from store s
where not exists (select 1
                  from dvd
                  where dvd.storeId = s.storeId and
                        exists (select 1
                                from movie m
                                where m.movieId = dvd.movieId and
                                      dvd.ProducerName <> 'BBC'
                               )
                 );

However, I find such nested combinations of exists / not exists (or the equivalent with in / not in to just be baffling -- much harder to understand than equivalent join versions.

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