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.