I am struggling with what looks to be relational division in sql. I need to filter data from the same table based on multiple criteria. Here-under is a schema of what my table looks like.
| -------|----------------|-----------------|----------------|
|ID |Question |RespondentId |Answer |
| -------|----------------|-----------------|----------------|
|1 |Big |1 |Yes |
|2 |Big |2 |Yes |
|3 |Big |3 |No |
|4 |Gender |1 |Male |
|5 |Gender |2 |Female |
|6 |Gender |3 |Female |
|7 |Children |1 |No |
|8 |Children |2 |Yes |
|9 |Children |3 |No |
--------------------------------------------------------------
I need the RespondenIds from this table called Answers that match the following filters : Question = Big and Children and Answer = Yes and Yes respectively for every question. Therefore, if I would have a correct Sql query my result should return me the following array : [2] since the only row that has the answer Yes for the question Big and the answer Yes for the question Children is the one with RespondentId = 2.
Also, the questions and the answers provided are not fixed and should be modular. For instance, I should be able to change an answer or removing a question without having to change the whole structure of my query.
Could you please help me finding a correct query for this problem ? I have been looking to a lot of explanations provided by @Erwin Brandstetter but none of them match my needs.
Advertisement
Answer
I would do this as:
select a.RespondentId
from Answers a
when (question, answer) in ( ('Big', 'Yes'), ('Children', 'Yes') )
group by RespondentId
having count(*) = 2 ;
This is easily generalized to:
with qa as (
select v.*
from (values ('Big', 'Yes'), ('Children', 'Yes')
) v(question, answer)
select a.RespondentId
from Answers a join
qa
on a.question = qa.question and a.answer = qa.answer
group by RespondentId
having count(*) = (select count(*) from qa);
This is pretty generalizable. You could even arrange the CTE to take an array or json argument and parse out into the separate comparison values.