Using a resultProxy object in sqlalchemy as a subquery - sql

I want to convert a resultproxy object into a subquery for use with an ORM query. What's the procedure to do this? I can't really find any examples.

A result proxy is something that you get when a SELECT statement is passed to the database and executed - at that point, there's no more "query" so in a literal sense, a result proxy isn't a subquery. However, that SELECT statement which you have executed, can instead not be executed and passed into another query as a subquery pretty easily:
from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class A(Base):
__tablename__ = 'a'
id = Column(Integer, primary_key=True)
data = Column(String)
e = create_engine("sqlite://", echo=True)
Base.metadata.create_all(e)
sess = Session(e)
# test data.
sess.add_all([A(data="d%d" % i) for i in range(10)])
sess.commit()
# a query.
subq = sess.query(A.id).filter(A.data.in_(["d3", "d4", "d5"]))
# execute subquery, gives us a list of tuples
list_of_tuples = subq.all()
# execute subquery via Core, gives us a ResultProxy
result_proxy = sess.execute(subq)
# inject subq into another Query as a subquery()
q = sess.query(A).filter(A.data.in_(subq.subquery()))
a_from_subquery = q.all()

Related

How SQL query Case and When works in django ORM?

I have a SQL query and when writing in Django ORM it returns an error. But the SQL query works perfectly on MySQL Command Line Client. Would anyone please explain the error or working of CASE and When in Django ORM?
SQL query:-
SELECT CASE WHEN LENGTH(au.first_name) < 1 THEN au.username ELSE concat(au.first_name,' ',au.last_name)
END AS fullname FROM rewards_usercard ru RIGHT JOIN auth_user au ON ru.user_id = au.id;
Django Models code:-
from django.db.models import Case, When, Q, CharField, Value
from django.db.models.functions import Length, Concat
from django.db.models.lookups import LessThan
queryset = UserCard.objects.annotate(
full_name = Case(
When(condition=Q(
LessThan(Length('user__first_name'),1)
), then='user__username'),
default = Concat('user__first_name', Value(' '), 'user__last_name'),
output_field=CharField()
)
)
Error:-
cannot unpack non-iterable LessThan object
Try this:
from django.db.models.functions import Coalesce, Concat
from django.db.models import (Case, CharField, When, Value)
data = UserCard.objects.all().annotate(fullname=Coalesce(Case(When(user__first_name__in=[None, ""], then="user__username"),default=Concat('user__first_name',Value(" "), 'user__last_name'),output_field=CharField()),"user__username")).values('fullname')

Query list index with django

i have a problem with django when i use these two arrays:
institution_ids [(2,), (16,)]
project_ids [(3,), (1,)]
in this query:
queryset = Patient.active.filter(tss_id__in=institution_ids, project_id__in = project_ids)
it gives me back all the combinations, but I need this kind of result:
queryset = Patient.active.filter(tss_id=institution_ids[0], project_id = project_ids[0])
queryset += Patient.active.filter(tss_id=institution_ids[1], project_id = project_ids[1])
how can i do?
Thanks
Giuseppe
What you search for is an OR statement.
You can do it using Q object.
In Django, we cannot directly use the OR operator to filter the
QuerySet. For this implementation, we have to use the Q() object. By
using the Q() object in the filter method, we will be able to use the
OR operator between the Q() objects.
For example-
If you want to get all objects with tss_id in institution array and all objects with project__id__in projects_id array you will use it like this.
queryset = Patient.active.filter(Q(tss_id__in=institution_ids) | project_id__in = project_ids))
Pay attention- you need to import Q.
Another option -
Using union
New in Django 1.11. Uses SQL’s UNION operator to combine the results of two or more QuerySets.
The UNION operator selects only distinct values by default. To allow duplicate values, use the all=True argument.
For example :
queryset = Patient.active.filter(tss_id=institution_ids[0], project_id = project_ids[0])
queryset2 = Patient.active.filter(tss_id=institution_ids[1], project_id = project_ids[1])
Combined_queryset = queryset.union(queryset2)

SQL alchemy ORM bracketing And statements with OR statements

I'm wondering if someone can help me convert this SQL query to SQL alchemy ORM. I am having issues in bracketing the And statements with Or statements. Here is a simpler version of the query I am trying to create:
SELECT * FROM [dbo].[UpcomingThings] WHERE ([Id] = 'ES1234' AND [Date] = '2021-08-18' AND [Period] = 27) OR ([Id] = 'ES0197' AND [Date] = '2021-08-18' AND [Period] = 29)
Note that Id in this case is not unique, so I have to rely on multiple other columns to make it unique. I have tried using .filter and .filter(_or()) in various combinations but I cant seem to get it so that its a WHERE (bracket and condition) OR (bracket and condition)
EDIT:
if sql alchemy was as simple as this, this is what i'd do assuming _or would give me an OR:
session.query(models.UpcomingThings).filter(UpcomingThings.Id == 'ES1234').filter(UpcomingThings.Period == 27).filter(UpcomingThings.SettlementDate == 2021-08-18).filter(or_(UpcomingThings.Id=='ES0197')).filter(UpcomingThings.Date == 2021-08-18)).filter(UpcomingThings.Period == 29))
Is there also no way I could do
session.query(models.UpcomingThings).filter(or_((AND STATEMENT), (AND STATEMENT))
I've tried to simply even do a .filter inside the or_ but obviously thats a syntax error!
Please can someone help convert this to SQLalchemy ORM! Thank you.
I think it will seem clear after the fact but you need to use and_ and or_ to achieve this. The call to filter() applies an implicit and_ but it won't work when you need the outer sql OR. This should do what you want to achieve. I tried to format it to make it more clear. or_ will join the conditions with sql OR and and_ will join the conditions with AND.
In one case you use SettlementDate and another just Date, should those be the same? I just changed it to SettlementDate to try the schema.
Python Example
#...
from sqlalchemy.sql import or_, and_
from datetime import date
class UpcomingThings(Base):
__tablename__ = 'upcoming_things'
Id = Column(String, primary_key=True, index=True)
Period = Column(Integer)
SettlementDate = Column(Date)
Base.metadata.create_all(engine)
with Session(engine) as session:
q = session.query(
UpcomingThings
).filter(
or_(
and_(
UpcomingThings.Id=='ES1234',
UpcomingThings.Period==27,
UpcomingThings.SettlementDate==date(year=2021, month=8, day=18)),
and_(
UpcomingThings.Id=='ES0197',
UpcomingThings.SettlementDate==date(year=2021, month=8, day=18),
UpcomingThings.Period==29)))
print (q)
Printed Output
SELECT upcoming_things."Id" AS "upcoming_things_Id", upcoming_things."Period" AS "upcoming_things_Period", upcoming_things."SettlementDate" AS "upcoming_things_SettlementDate"
FROM upcoming_things
WHERE upcoming_things."Id" = ? AND upcoming_things."Period" = ? AND upcoming_things."SettlementDate" = ? OR upcoming_things."Id" = ? AND upcoming_things."SettlementDate" = ? AND upcoming_things."Period" = ?

Passing a parameter to a sql query using pyodbc failing

I have read dozens of similar posts and tried everything but I still get an error message when trying to pass a parameter to a simple query using pyodbc. Apologies if there is an answer to this elsewhere but I cannot find it
I have a very simple table:
select * from Test
yields
a
b
c
This works fine:
import pyodbc
import pandas
connection = pyodbc.connect('DSN=HyperCube SYSTEST',autocommit=True)
result = pandas.read_sql("""select * from Test where value = 'a'""",connection,params=None)
print(result)
result:
value
0 a
However if I try to do the where clause with a parameter it fails
result = pandas.read_sql("""select * from Test where value = ?""",connection,params='a')
yields
Error: ('01S02', '[01S02] Unknown column/parameter value (9001) (SQLPrepare)')
I also tried this
cursor = connection.cursor()
cursor.execute("""select * from Test where value = ?""",['a'])
pyodbcResults = cursor.fetchall()
and still received the same error
Does anyone know what is going on? Could it be an issue with the database I am querying?
PS. I looked at the following post and the syntax there in the first part of answer 9 where dates are passed by strings looks identical to what I am doing
pyodbc the sql contains 0 parameter markers but 1 parameters were supplied' 'hy000'
Thanks
pandas.read_sql(sql, con, index_col=None, coerce_float=True, params=None, parse_dates=None, columns=None, chunksize=None)[https://pandas.pydata.org/pandas-docs/stable/generated/pandas.read_sql.html]¶
params : list, tuple or dict, optional, default: None
example:
cursor.execute("select * from Test where value = %s",['a'])
or Named arguments example:
result = pandas.read_sql(('select * from Test where value = %(par)s'),
db,params={"par":'p'})
in pyodbc write parms directly after sql parameter:
cursor.execute(sql, *parameters)
for example:
onepar = 'a'
cursor.execute("select * from Test where value = ?", onepar)
cursor.execute("select a from tbl where b=? and c=?", x, y)

How can I prioritize the order of the fields in the filter

When I get the objects,
objs = Page.objects.get(slug="some-slug.html", web_id=1)
the SQL query generated is
select * from cms_page WHERE ("cms_page"."web_id" = '1' AND "cms_page"."slug" = '''some-slug''')
I would like change the SQL to
select * from cms_page WHERE ("cms_page"."slug" = '''some-slug''' and "cms_page"."web_id" = '1' )
First slug field, because the slug field is a index (Exist index with this field)
class Page(models.Model):
title = models.CharField(max_length=128)
body = models.TextField(blank=True)
slug = models.CharField(max_length=200, db_index=True)
web = models.ForeignKey(Web, editable=False)
def __unicode__(self):
return self.title
def save(self, *args, **kwargs):
if not self.slug:
self.slug = "{0}{1}".format(slugify(self.title),".html")
super(Page,self).save(*args,**kwargs)
class Meta:
unique_together = ("web", "slug")
index_together = ["web", "slug"]
For most databases, this query is exactly the same as
select * from cms_page WHERE ("cms_page"."web_id" = '1' AND "cms_page"."slug" = '''some-slug''')
This one
select * from cms_page WHERE ("cms_page"."slug" = '''some-slug''' and "cms_page"."web_id" = '1' )
You might be tempted to rewrite your queries to make arithmetic
operations faster, while sacrificing readability. Because MySQL does
similar optimizations automatically, you can often avoid this work,
and leave the query in a more understandable and maintainable form.
Some of the optimizations performed by MySQL follow:
http://dev.mysql.com/doc/refman/5.7/en/where-optimizations.html
Now, mysql isn't so hot about using indexes as postgresql is, so if mysql does, it postgresql does it too!
If an index is available, the RDBMS query parser will decide to perform the comparision on those columns that are covered by the index first.