Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SqlAlchemy: filter to match all instead of any values in list?

I want to query a junction table for the value of column aID that matches all values of a list of ids ids=[3,5] in column bID.

This is my junction table (JT):

 aID    bID
   1      1
   1      2
   2      5
   2      3
   1      3
   3      5

I have this query: session.query(JT.aID).filter(JT.bID.in_(ids)).all()

This query returns the aID values 1, 2 and 3 because they all have rows with either 3 or 5 in the bID column. What I want the query to return is 2 because that is the only aID value that has all values of the ids list in its bID column.

Don't know how to explain the problem better, but how can I get to the result?

like image 425
boadescriptor Avatar asked Nov 12 '12 19:11

boadescriptor


People also ask

What does all () do in SQLAlchemy?

all() method. The Query object, when asked to return full entities, will deduplicate entries based on primary key, meaning if the same primary key value would appear in the results more than once, only one object of that primary key would be present. This does not apply to a query that is against individual columns.

What is difference between filter and filter by in SQLAlchemy?

The second one, filter_by(), may be used only for filtering by something specifically stated - a string or some number value. So it's usable only for category filtering, not for expression filtering. On the other hand filter() allows using comparison expressions (==, <, >, etc.)

What does SQLAlchemy all () return?

As the documentation says, all() returns the result of the query as a list.

Is there something better than SQLAlchemy?

Django, Pandas, Entity Framework, peewee, and MySQL are the most popular alternatives and competitors to SQLAlchemy.


2 Answers

Based on @Gordon Linoff answer and with two tables A and B where A has a relation one- to-many towards B called A.bs the SqlAlchemy equivalent would be:

from sqlalchemy import func  
session.query(A).join(B).filter(B.id.in_(<your_list>)).group_by(A.id).having(func.count(A.bs) == len(<your_list>)).all()
like image 80
El Bert Avatar answered Oct 05 '22 23:10

El Bert


You are looking for a query that works on sets of rows. I think a group by with having clause is the best approach:

select aid
from jt
where bid in (<your list>)
group by aid
having count(distinct bid) = 2

If you can put the ids that you desire in a table, you can do the following more generic approach:

select aid
from jt join
     bids
     on jf.bid = bids.bid
group by aid
having count(distinct jt.bid) = (select count(*) from bids)
like image 39
Gordon Linoff Avatar answered Oct 05 '22 23:10

Gordon Linoff