Stephanie
Stephanie

Reputation: 516

How to count different values in a column and same group

I have to distinguish different values in a group, how do I perform that? Example of my table:

Person  Status
1       Y
2       N
3       Y
3       N

-If a person only has Y status then display Yes

-If a person only has N status then display No

-If a person has both Y and N status then display No

Result:

Person  Status
1       Yes
2       No
3       No

How do I perform last logic when a person has both status? Here is the statement I tried which worked but I am not 100% sure if it is accurate:

CASE WHEN SUM(CASE WHEN Status = 'Y' THEN 1 ELSE 0 END)>=1 AND SUM(CASE WHEN Status = 'N' THEN 1 ELSE 0 END)>=1 THEN 'No' 
    WHEN SUM(CASE WHEN Status  = 'Y' THEN 1 ELSE 0 END)>=1 THEN 'Yes'
ELSE 'No'END

Upvotes: 0

Views: 498

Answers (2)

Robert Andrzejuk
Robert Andrzejuk

Reputation: 5232

Checking your query

For simplicity let's say that:

(Y) -> SUM(CASE WHEN Status = 'Y' THEN 1 ELSE 0 END)
(N) -> SUM(CASE WHEN Status = 'N' THEN 1 ELSE 0 END) 

So your query can be written as pseudocode:

case when (Y)>=1 and (N)>=1 then 'No'
     when (Y)>=1 then 'Yes'
     else 'No'
end

To check if your query is correct You need to build a truth table from your query for all possible input:

  (Y) | (N)      (Y)>=1 | (N)>=1      (Y)>=1 and (N)>=1      Result
 -----------    -----------------    -------------------    --------
   0  |  0        false | false             false             'No'
   0  | >=1   =>  false | true    =>        false        =>   'No'
  >=1 |  0        true  | false             false             'Yes'
  >=1 | >=1       true  | true              true              'No'

Look's like You got it right!

Creating a correct condition

To be sure if You are making your condition correctly You need to build a truth table:

(1)
    Yes   |    No     | Result
-------------------------------
found     | found     | No
not found | found     | No
found     | not found | Yes
not found | not found | Null

or

(2)
         \       No  
    Yes   \ Found | Not Found |
-------------------------------
 Found     |  No  |    Yes    |
-------------------------------
 Not Found |  No  |    Null   |
 ------------------------------

The first thing to notice is that if status==No is found the result is always No.

Only when a No is not found and a Yes is found then we return Yes.

So Your condition can be written with a nested case.

select columns, ....
(
  case when (SUM(CASE WHEN Status = 'N' THEN 1 ELSE 0 END)>=1) then 'No'
       else case when (SUM(CASE WHEN Status = 'Y' THEN 1 ELSE 0 END)>=1) then 'Yes'
                 else NULL
            end
  end
) as result

It's easy with 2 variables in a condition.
If You have more variables then I suggest You look into a Karnaugh map

Checking the 'MIN' answer

Another answer here gave an original solution:

select CASE WHEN MIN(status) = 'Y' THEN 'Yes' ELSE 'No' END
, Person
from table
group by Person

Is it correct?

Let's check first all the possible input.

Input:
{Y} - contains only Y in the column
{N} - contains only N in the column
{Y,N} - contains Y and N in the column
{} - Y and N do not appear in the column

Let's calculate all the possible results:

Input        MIN(status)      Result
-------     -------------    --------
 {Y}             Y             Yes
 {N}     =>      N        =>   No
 {Y,N}           N             No
 {}             NULL           No

It's a correct answer.

Upvotes: 0

artm
artm

Reputation: 8584

You can use MIN:

select CASE WHEN MIN(status) = 'Y' THEN 'Yes' ELSE 'No' END
, Person
from table
group by Person

Upvotes: 1

Related Questions