How to write subquery in django - python

Is it possible to make following sql query in django
select * from (
select * from users
) order by id
It is just minimal example. I have a long subquery instead of select * from users. But I can't understand how insert it into subquery.
UPDATED:
Subquery from doc doesn't suits because it build following request
SELECT "post"."id", (
SELECT U0."email"
FROM "comment" U0
WHERE U0."post_id" = ("post"."id")
ORDER BY U0."created_at" DESC LIMIT 1
) AS "newest_commenter_email" FROM "post"
and this subquery can return only one value (.values('email')).
Construction select (subquery) as value from table instead of select value from (subquery)

i would use a python connector to postgreSQL - http://www.postgresqltutorial.com/postgresql-python/query/, that is what i do for the mysql, thought did not try for the postgresql

Making a subquery is essentially setting up two queries and using one query to "feed" another:
from django.db.models import Subquery
all_users = User.objects.all()
User.objects.annotate(the_user=Subquery(all_users.values('email')[:1]))
This is more or less the same as what you provided. You can get about as complicated as you'd like here but the best source to get going with subqueries is the docs

Related

How to make a QuerySet with custom select in django

I'm working on a project in python I'm kind of a beginner. I searched a bit on the Queryset but didn't found out how to do a custom select query. Here's the raw SQL query :
SELECT
DATE_FORMAT(
DATE_ADD(date_and_time, INTERVAL - WEEKDAY(date_and_time) DAY), '%Y-%m-%d'
) as Week,
device_type as 'Type of device',
COUNT(*) as Views FROM manage_history
GROUP BY Week, device_type;
How could I get the values but with a QuerySet ?
Thanks a lot
You can perform a raw sql query. More details at https://docs.djangoproject.com/en/3.0/topics/db/sql/
Django's default manager gives you RawQuerySet:
>>> from api.models import Song
>>> Song.objects.raw('SELECT * FROM api_song')
<RawQuerySet: SELECT * FROM api_song>
In case of that you want exactly QuerySet to be returned, Take a look Here.

Sqlalchemy query order

I'm refactoring my flask app and am wondering how flask-sqlalchemy works - from right to left or vice versa.
For example, does this command first filter then order and select all, or select all, order, then filter?
items = db.session.query(MyDbModel).filter_by(status=1).order_by(desc('created')).all()
Translating to SQL it would be
SELECT * FROM MyDbModel
WHERE status = 1
ORDER BY created DESC
You can actually see the SQL query if you print the query before all() operator.
print(str(q))
Where q is your query object before all() function.
So, answering your question, it first filters, then order.

Django ORM: Get latest record for distinct field

I'm having loads of trouble translating some SQL into Django.
Imagine we have some cars, each with a unique VIN, and we record the dates that they are in the shop with some other data. (Please ignore the reason one might structure the data this way. It's specifically for this question. :-) )
class ShopVisit(models.Model):
vin = models.CharField(...)
date_in_shop = models.DateField(...)
mileage = models.DecimalField(...)
boolfield = models.BooleanField(...)
We want a single query to return a Queryset with the most recent record for each vin and update it!
special_vins = [...]
# Doesn't work
ShopVisit.objects.filter(vin__in=special_vins).annotate(max_date=Max('date_in_shop').filter(date_in_shop=F('max_date')).update(boolfield=True)
# Distinct doesn't work with update
ShopVisit.objects.filter(vin__in=special_vins).order_by('vin', '-date_in_shop).distinct('vin').update(boolfield=True)
Yes, I could iterate over a queryset. But that's not very efficient and it takes a long time when I'm dealing with around 2M records. The SQL that could do this is below (I think!):
SELECT *
FROM cars
INNER JOIN (
SELECT MAX(dateInShop) as maxtime, vin
FROM cars
GROUP BY vin
) AS latest_record ON (cars.dateInShop= maxtime)
AND (latest_record.vin = cars.vin)
So how can I make this happen with Django?
This is somewhat untested, and relies on Django 1.11 for Subqueries, but perhaps something like:
latest_visits = Subquery(ShopVisit.objects.filter(id=OuterRef('id')).order_by('-date_in_shop').values('id')[:1])
ShopVisit.objects.filter(id__in=latest_visits)
I had a similar model, so went to test it but got an error of:
"This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery"
The SQL it generated looked reasonably like what you want, so I think the idea is sound. If you use PostGres, perhaps it has support for that type of subquery.
Here's the SQL it produced (trimmed up a bit and replaced actual names with fake ones):
SELECT `mymodel_activity`.* FROM `mymodel_activity` WHERE `mymodel_activity`.`id` IN (SELECT U0.`id` FROM `mymodel_activity` U0 WHERE U0.`id` = (`mymodel_activity`.`id`) ORDER BY U0.`date_in_shop` DESC LIMIT 1)
I wonder if you found the solution yourself.
I could come up with only raw query string. Django Raw SQL query Manual
UPDATE "yourapplabel_shopvisit"
SET boolfield = True WHERE date_in_shop
IN (SELECT MAX(date_in_shop) FROM "yourapplabel_shopvisit" GROUP BY vin);

How to make a subquery in sqlalchemy

SELECT *
FROM Residents
WHERE apartment_id IN (SELECT ID
FROM Apartments
WHERE postcode = 2000)
I'm using sqlalchemy and am trying to execute the above query. I haven't been able to execute it as raw SQL using db.engine.execute(sql) since it complains that my relations doesn't exist... But I succesfully query my database using this format: session.Query(Residents).filter_by(???).
I cant not figure out how to build my wanted query with this format, though.
You can create subquery with subquery method
subquery = session.query(Apartments.id).filter(Apartments.postcode==2000).subquery()
query = session.query(Residents).filter(Residents.apartment_id.in_(subquery))
I just wanted to add, that if you are using this method to update your DB, make sure you add the synchronize_session='fetch' kwarg. So it will look something like:
subquery = session.query(Apartments.id).filter(Apartments.postcode==2000).subquery()
query = session.query(Residents).\
filter(Residents.apartment_id.in_(subquery)).\
update({"key": value}, synchronize_session='fetch')
Otherwise you will run into issues.

SQLAlchemy: How to select max from several tables

I am starting to use sqlalchemy in an ORM way rather than in an SQL way. I have been through the doc quickly but I don't find how to easily do the equivalent of SQL:
select max(Table1.Date) from Table1, Table2
where...
I can do:
session.query(Table1, Table2)
...
order_by(Table1.c.Date.desc())
and then select the first row but it must be quite inefficient. Could anyone tell me what is the proper way to select the max?
Many thanks
Ideally one would know the other parts of the query. But without any additional information, below should do it
import sqlalchemy as sa
q = (
session
.query(sa.func.max(Table1.date))
.select_from(Table1, Table2) # or any other `.join(Table2)` would do
.filter(...)
.order_by(Table1.c.Date.desc())
)

Categories

Resources