0

I have the table PETS with columns Index, Owner and Animal with following rows:

Index, Owner, Animal
--------------------
1, Anne, cat
2, Anne, dog
3, Anne, rabbit
4, Bill, dog
5, Bill, dog
6, Bill, rabbit
7, John, cat
8, John, dog
9, Johh, parrot
10, Susy, rabbit
11, Susy, parrot
12, Susy, parrot

I need two outputs: Get all Owners which own

  1. a cat OR a dog
  2. a cat AND a dog

The first output I get with IN as shorthand operator for OR:

SELECT DISTINCT Owner FROM PETS WHERE Animal IN ('cat','dog')

Is there an equivalent shorthand operator for AND? The solution in this thread with HAVING COUNT does not quite work as it returns 'Bill' as there is 'dog' twice, however there is no 'cat'.

stonebe
  • 482
  • 1
  • 3
  • 14

2 Answers2

0

There isn't a shorthand, no, but personally I would use a HAVING with conditional aggregation for the owning both logic:

SELECT Owner
FROM dbo.Pets
GROUP BY Owner
HAVING COUNT(CASE Animal WHEN 'dog' THEN 1 END) > 0
   AND COUNT(CASE Animal WHEN 'cat' THEN 1 END) > 0;

And, obviously, you can easily change the above for your original requirement by changing the AND to an OR.

Thom A
  • 88,727
  • 11
  • 45
  • 75
0

The solution with HAVING COUNT does not quite work as it returns 'Bill' as there is 'dog' twice, however there is no 'cat'.

IN ('cat','dog') selects all owners which have a cat or a dog (consequently, owners which have a cat AND a dog). From the above cat_and/or_dog_owners, the count must be on DISTINCT animals: if a cat_and/or_dog_owner has 2 distinct animals then the owner has both a cat and a dog:

declare @t table (Id smallint, Owner varchar(10), Animal varchar(10))
insert into @t
values
--------------------
(1, 'Anne', 'cat'),
(2, 'Anne', 'dog'),
(3, 'Anne', 'rabbit'),
(4, 'Bill', 'dog'),
(5, 'Bill', 'dog'),
(6, 'Bill', 'rabbit'),
(7, 'John', 'cat'),
(8, 'John', 'dog'),
(9, 'Johh', 'parrot'),
(10, 'Susy', 'rabbit'),
(11, 'Susy', 'parrot'),
(12, 'Susy', 'parrot'),
(13, 'Susy', 'cat');--n

select owner , concat(min(animal), case when count(distinct animal) = 2 then ' & ' end, nullif(max(animal), min(animal))) as cat_dog_pet
from @t
WHERE Animal IN ('cat','dog')
group by owner;
lptr
  • 1
  • 2
  • 6
  • 16