sqlalchemy add entity from a subquery - python

I want to use outerjoin operation on a subquery and also include values from the subquery also.
My code
q_responses = session.query(Candidate, CandidateProfile)
.join(CandidateProfile, CandidateProfile.candidate_id == Candidate.id)
subq = (session.query(AppAction.candidate_id, Activity.archived)\
.join(Activity, and_(AppAction.candidate_id == Activity.candidate_id,
Activity.archived == 1)))\
.subquery("subq")
responses = q_responses.outerjoin(subq, Candidate.id == subq.c.candidate_id).all()
So I get the result in this format
(Candidate, CandidateProfile)
But I also want to include the archived value from subquery in the result.
By reading many relevant posts from the internet, I have tried
add_entity(subq.c.archived)
with_entities
add_column
select_from
But all those have resulted in some error.
Please help me out.

Please share your error for when you try add_column. The code below should work just fine (assuming that it does work without like which contains add_column):
responses = (
q_responses
.add_column(subq.c.archived) # #new
.outerjoin(subq, Candidate.id == subq.c.candidate_id)
).all()
Also you could have created a query straight away with this column included:
subq = (
session.query(AppAction.candidate_id, Activity.archived)
.join(Activity, and_(AppAction.candidate_id == Activity.candidate_id,
Activity.archived == 1))
).subquery("subq")
q_responses = (
session.query(Candidate, CandidateProfile, subq.c.archived)
.join(CandidateProfile, CandidateProfile.candidate_id == Candidate.id)
.outerjoin(subq, Candidate.id == subq.c.candidate_id)
).all()

Related

How to union two counts queries in SQLAlchemy?

I have two queries and the only difference between then is that one is counting the success status and the other failure status. Is there a way to get this result in just one query? I'm using SQLALchemy to do the queries.
success_status_query = (
db_session.query(Playbook.operator, func.count(Playbook.operator).label("success"))
.filter(Playbook.opname != "failed")
.join(AccountInfo, AccountInfo.hardware_id == Playbook.hardware_id)
.group_by(Playbook.operator)
)
failure_status_query = (
db_session.query(Playbook.operator, func.count(Playbook.operator).label("failure"))
.filter(Playbook.opname == "failed")
.join(AccountInfo, AccountInfo.hardware_id == Playbook.hardware_id)
.group_by(Playbook.operator)
)
You can use conditions on Count, your query will look like:
query = (
db_session.query(
Playbook.operator,
func.count(
case(
[((Playbook.opname != "failed"), Playbook.operator)],
else_=literal_column("NULL"),
)
).label("success"),
func.count(
case(
[((Playbook.opname == "failed"), Playbook.operator)],
else_=literal_column("NULL"),
)
).label("failure"),
)
.join(AccountInfo, AccountInfo.hardware_id == Playbook.hardware_id)
.group_by(Playbook.operator)
)
you can use the or_() operator like the sample bellow:
from sqlalchemy import or_
stmt = select(users_table).where(
or_(
users_table.c.name == 'wendy',
users_table.c.name == 'jack'
)
)
It won't be a straight swap, but you will be able to work it out.
You can find more information in the SQLAlchemy documentation:
https://docs.sqlalchemy.org/en/14/core/sqlelement.html#sqlalchemy.sql.expression.or_

How to convert a postgresql not exists to sqlalchemy(1.x)?

I'm trying to convert an sql query into an sqlalchemy one and I'm having trouble with translating a "where not exists(select...)" part.
Here's the base query that I wish to convert to sqlalchemy:
select sd.address,
sd.colour_code,
s.id as deactivated_id,
s.type,
'http://site/groups/' || c.group_id || '/user/' || c.subject_id as URL
from sensors s
join contracts c on s.contract_id=c.id
join sensordevices sd on sd.id=s.device_id
where s.begin_time != null and
s.end_time != null and
c.end_date != and
not exists (select * from sensors sb
where sb.begin_time != null and --b properly entered
sb.end_time == null and -- b active
sb.contract_id==s.contract_id and
s.type==sb.type and
s.end_time<=sb.begin_time)
;
This is where I left the code(erroneous code) after my last tries:
s = aliased(SensorInstance)
sb = aliased(SensorInstance)
sd = aliased(SensorDevice)
c = aliased(Contract)
info = db.session.query(sd.address,sd.colour_code,s.id,s.role,c.group_id,c.resident_id)\
.filter(s.contract_id==c.id)\
.filter(s.device_id==sd.id)\
.filter(s.begin_time != None)\
.filter(s.end_time != None)\
.filter(c.end_date != None)\
.filter(sd.device_type == device_type)\
.filter(sd.address == device_address)\
.filter(not_(and_(sb.begin_time != None,
sb.end_time == None,
sb.role==s.role,
sb.contract_id==s.contract_id,
s.end_time<=sb.begin_time).exists())).first()
Which produces a 'Comparator' object has no attribute 'exists' which is a reasonable error.
Another thing that I have tried is this (with the same aliases as above):
info = db.session.query(sd.address,sd.colour_code,s.id,s.role,c.group_id,c.resident_id)\
.filter(s.contract_id==c.id)\
.filter(s.device_id==sd.id)\
.filter(s.begin_time != None)\
.filter(s.end_time != None)\
.filter(c.end_date != None)\
.filter(sd.device_type == device_type)\
.filter(sd.address == device_address)\
.filter(~exists().where(and_(sb.begin_time != None,
sb.end_time == None,
sb.role==s.role,
sb.contract_id==s.contract_id,
s.end_time<=sb.begin_time).exists())).first()
Which produces a sqlalchemy.exc.ProgrammingError: (psycopg2.errors.SyntaxError) SELECT * with no tables specified is not valid LINE 3: ...sordevices_1.address = 4278262373 AND NOT (EXISTS (SELECT *
error. (This I tried to do based on the solution provided here
Does anyone have any pointers or a solution on how to fix this?
Thank you very much!
Without being able to test because I dont have access to data I believe the second approach can work but as the error says you have a malformed subquery. You are making a select without specifying the table (or object in this cas of orm) where the subquery operates on.
Basically I think you mees to make a subquery of the form:
subquery = ~db.session.query(sd.address,sd.colour_code,s.id,s.role,c.group_id,c.resident_id)\
.filter(sb.begin_time is not None,
sb.end_time is None,
sb.role==s.role,
sb.contract_id==s.contract_id,
s.end_time<=sb.begin_time).exists()
For more details see here this thread

SQLAlchemy filter query with multiple table outerjoin

I have following three tables.
User:
[
user_id
first_name
last_name
]
Picture:
[
filename
picture_type // eg: painting, photograph
painter
]
Comment
[
user_id
filename
comment
]
I am trying to query all filenames that was not reviewed by current user.
following line returns all the filenames that was reviewed and commented in the given picture_type
session.query(Picture.filename).outerjoin(Comment).filter(
Picture.filename == Comment.filename,
Picture.picture_type == 'photograph'
).all()
, and the following line returns all the filenames in the in the given picture_type
session.query(Picture.filename).outerjoin(Comment).filter(
Picture.picture_type == 'photograph'
).all()
I was expecting following line would return filenames not reviewed in the in the given picture_type, but it returns an empty list
session.query(Picture.filename).outerjoin(Comment).filter(
Picture.filename != Comment.filename,
Picture.picture_type == 'photograph'
).all()
Am I doing something wrong here? What am I missing here?
i think your code have syntax error. are you missed a dot ? you wrote:
session.query(Picture.filename)outerjoin(Comment).filter(
Picture.filename == Comment.filename,
Picture.picture_type == 'photograph'
).all()
but it should be like this:
session.query(Picture.filename).outerjoin(Comment).filter(
Picture.filename == Comment.filename,
Picture.picture_type == 'photograph'
).all()
other sections also has this problem
I researched Exclusive Join and figured out the problem.
It should have been None == Comment.filename, not Picture.filename != Comment.filename.
I fixed the code like below code and it is working now.
session.query(Picture.filename).outerjoin(Comment).filter(
None == Comment.filename,
Picture.picture_type == 'photograph'
).all()
The problem was the resulting table of left outer join would not have any row that meet left_field != right_field condition. The resulting rows would meet conditions left_field == right_field or None == right_field since the missing value in the right table would be marked as null in the resulting table.
Below link gave me good learnings about this subject.
http://www.datasavantconsulting.com/roland/sql_excl.html
Thanks all for trying to help.
However, I will still be open to better suggestions!!!

SQLAlchemy search using varying keywords

Im struggling at a very specific problem here:
I need to make a LIKE search in SQLAlchemy, but the amount of keywords are varying.
Heres the code for one keyword:
search_query = request.form["searchinput"]
if selectet_wg and not lagernd:
query = db_session.query(
Artikel.Artnr,
Artikel.Benennung,
Artikel.Bestand,
Artikel.Vkpreisbr1
).filter(
and_(
Artikel.Benennung.like("%"+search_query+"%"),
Artikel.Wg == selectet_wg
)
).order_by(Artikel.Vkpreisbr1.asc())
"searchinput" looks like this : "property1,property2,property3", but also can be just 1,2,5 or more propertys.
I want to split the searchinput at "," (yes i know how to do that :) ) and insert another LIKE search for every property.
So for the above example the search should be looking like this:
search_query = request.form["searchinput"]
if selectet_wg and not lagernd:
query = db_session.query(
Artikel.Artnr,
Artikel.Benennung,
Artikel.Bestand,
Artikel.Vkpreisbr1
).filter(
and_(
Artikel.Benennung.like("%"+search_query+"%"), #property1
Artikel.Benennung.like("%"+search_query+"%"), #property2
Artikel.Benennung.like("%"+search_query+"%"), #property3
Artikel.Wg == selectet_wg
)
).order_by(Artikel.Vkpreisbr1.asc())
I dont think its a smart idea just to make an if statement for the amount of propertys and write down the query serveral times...
Im using the newest version of sqlalchemy and python 3.4
It should be possible to create a list of you like filters and pass them all to and_.
First create a list of the like queries:
search_queries = search_query.split(',')
filter = [Artikel.Benennung.like("%"+sq"%") for sq in search_queries]
Then pass them to and_, unpacking the list:
and_(
Artikel.Wg == selectet_wg,
*filter
)
*filter has to be the last argument to and_ otherwise python will give you an error.
You can call filter multiple times:
search_query = request.form["searchinput"]
if selectet_wg and not lagernd:
query = db_session.query(
Artikel.Artnr,
Artikel.Benennung,
Artikel.Bestand,
Artikel.Vkpreisbr1
).filter(Artikel.Wg == selectet_wg)
for prop in search_query.split(','):
query = query.filter(Artikel.Benennung.like("%"+prop+"%"))
query = query.order_by(Artikel.Vkpreisbr1.asc())

Can I dynamically change order_by attributes in my query call?

I have the following query call:
SearchList = (DBSession.query(
func.count(ExtendedCDR.uniqueid).label("CallCount"),
func.sum(ExtendedCDR.duration).label("TotalSeconds"),
ExtendedCDR,ExtensionMap)
.filter(or_(ExtensionMap.exten == ExtendedCDR.extension,ExtensionMap.prev_exten == ExtendedCDR.extension))
.filter(between(ExtendedCDR.start,datebegin,dateend))
.filter(ExtendedCDR.extension.in_(SelectedExtension))
.group_by(ExtendedCDR.extension)
.order_by(func.count(ExtendedCDR.uniqueid).desc()))
.all()
)
I would like to be able to define the order_by clause prior to calling the .query(), is this possible?
I tried doing as this stackoverflow answer suggests for a filter spec, but I had no idea how to create the filter_group syntax.
From that post:
filter_group = list(Column.in_('a','b'),Column.like('%a'))
query = query.filter(and_(*filter_group))
You build a SQL query with the DBSession.query() call, and this query is not executed until you call .all() on it.
You can store the intermediary results and add more filters or other clauses as needed:
search =DBSession.query(
func.count(ExtendedCDR.uniqueid).label("CallCount"),
func.sum(ExtendedCDR.duration).label("TotalSeconds"),
ExtendedCDR,ExtensionMap)
search = search.filter(or_(
ExtensionMap.exten == ExtendedCDR.extension,
ExtensionMap.prev_exten == ExtendedCDR.extension))
search = search.filter(between(ExtendedCDR.start, datebegin, dateend))
search = search.filter(ExtendedCDR.extension.in_(SelectedExtension))
search = search.group_by(ExtendedCDR.extension)
search = search.order_by(func.count(ExtendedCDR.uniqueid).desc())
The value you pass to order_by can be created ahead of time:
search_order = func.count(ExtendedCDR.uniqueid).desc()
then used like:
search = search.order_by(search_order)
Once your query is complete, get the results by calling .all():
SearchList = search.all()

Categories