Исключить из вывода, если в столбце есть какая-либо запись, отличная от xyz

#sql #sql-server

#sql #sql-сервер

Вопрос:

Я пытаюсь вывести строки, в которых почтовые индексы содержат записи ТОЛЬКО категории a — например, в таблице ниже:

 Id | Category | Name | ZipCode | Extraneous
--------------------------------------------
1      a         Jim    1234      a comment
2      a         Jim    1234      other
3      b         Jim    1234      no way
4      a         Baz    5678      foobar
5      c         Gil    0000      jiminy
6      a         Amy    0000      wibble
  

Я должен получать только строку 4. Я не хочу, чтобы zipcode 1234 отображался, даже если в нем есть a запись, потому что в нем также есть запись для категории b — аналогично Zipcode 0000 имеет запись для c so, которая не должна отображаться.

Пока я делаю:

 select max(t1.Id),
    t1.Category,
    t1.Name,
    t1.ZipCode,
    t1.Extraneous
from tbl t1
join tbl t2 on t1.Zipcode = t2.Zipcode
where t1.Category = 'a'
and t2.Category != 'b' and t2.Category != 'c'
group by
    t1.Category,
    t1.Name,
    t1.ZipCode,
    t1.Extraneous
  

Который по-прежнему дает результаты для почтового индекса 1234

Как мне получить все экземпляры почтового индекса, в которых есть записи для b , но только если у них нет других записей категории?

Комментарии:

1. select distinct здесь не требуется, ваш GROUP BY не вернет никаких дубликатов.

2. @jarlh спасибо за совет — я удалю это

Ответ №1:

Использование не существует:

 select
a.*

from
table1 a
where not exists (select zipcode from table1 b where a.zipcode = b.zipcode and b.category <> 'A')
and a.category = 'A'
  

Ответ №2:

Вы можете просто использовать not exists :

 select t.*
from tbl t
where not exists (select 1
                  from tbl t2
                  where t2.zipcode = t.zipcode and t2.category <> 'A'
                 );
  

Вы также можете использовать оконные функции. Например:

 select t.*
from (select t.*,
            sum(case when category = 'a' then 0 else 1 end)
            over (partition by zipcode) as cnt_nota
     from tbl t
    ) t
where cnt_nota = 0;
  

Комментарии:

1. Как всегда, спасибо, Гордон. Работает как шарм.

Ответ №3:

Можно использовать except ..

     select zipcode
    from table1
    where category = 'a'
    except
    select zipcode
    from table1
    where category <> 'a'
  

Комментарии:

1. Это просто выводит почтовый индекс, а не всю строку данных, как только я добавляю другие столбцы к выборкам, он снова выводит другие строки.

2. Извините, я неправильно понял вопрос. Не заметил «все строки». Похоже, у вас уже есть ответ, поэтому я не буду утруждать себя исправлением этого.