Search code examples
postgresqlsubqueryrelational-division

Is there a way to select elements associated with checked items without using multiple SELECT statements?


I'm trying to make a query that selects the neighborhoods ids of places that only have all the transport checked in a checkbox list. For instance, if 'Bus' and 'Railway' are checked, it should give me 7,8, and if only 'Railway' is checked, it should give me 7,8,11. The 'transporte' table is like this

     b_codigo | tipo_transporte
    ----------+-----------------
            1 | Underground
            1 | Bus
            2 | Bus
            2 | Underground
            3 | Bus
            3 | Underground
            4 | Bus
            4 | RENFE
            4 | Underground
            5 | RENFE
            5 | Underground
            5 | Bus
            5 | Tram
            6 | Bus
            6 | Underground
            7 | RENFE
            7 | Underground
            7 | Bus
            7 | Railway (FGC)
            8 | Underground
            8 | Railway (FGC)
            8 | Bus
            9 | Underground
            9 | Bus
           10 | Underground
           10 | Bus
           11 | Railway (FGC)
           11 | Underground
           12 | Bus

I tried with a query of the form

SELECT DISTINCT b_codigo 
FROM transporte 
WHERE (b_codigo, 'checked1') IN (SELECT * FROM transporte) 
  AND (b_codigo, 'checked2') IN (SELECT * FROM transporte) 
  AND ...

and another of the form

SELECT b_codigo 
FROM transporte 
WHERE tipo_transporte = 'checked1' 
INTERSECT 
SELECT b_codigo 
FROM transporte 
WHERE tipo_transporte = 'checked2' 
INTERSECT 
...;

and both give me the same results, but I'm worried about the efficiency of this two queries.

Is there a way of doing the same query without using N SELECT statements with N the number of checked boxes?


Solution

  • One way to do it, is to use aggregation:

    select b_codigo
    from transporte
    where tipo_transporte in ('Bus', 'Railway (FGC)')
    group by b_codigo
    having count(distinct tipo_transporte) = 2
    

    The number to compare to with the HAVING clause, needs to match the number of elements for the IN clause.