Django left join with and condition - django

I have 3 models Product,Photo,ProductLikeDislike. I am left joining all the three. For that I wrote this query:
x=Product.objects.values_list('name','photo','productlikedislike')
Through this I am getting correct left join I printed and checked like this:
Note: olx is the name of my Django app.
print(x.query)
SELECT "olx_product"."name", "olx_photo"."id", "olx_productlikedislike"."id"
FROM "olx_product" LEFT OUTER JOIN "olx_photo" ON ("olx_product"."id" =
"olx_photo"."reference_id_id") LEFT OUTER JOIN "olx_productlikedislike" ON
("olx_product"."id" = "olx_productlikedislike"."product_id_id") ORDER BY
"olx_product"."created" DESC
Now I want to add extra and condition along with ON statement like this:
ON ("olx_product"."id" =
"olx_productlikedislike"."product_id_id"
and "olx_productlikedislike"."product_liked_by_id"=2)
So for this somebody suggested me that use Django's FilteredRelation. I used but it is not adding extra and condition along with ON
I used FilteredRelation like this:
x=Product.objects.annotate(
productlikedislike_product_liked_by_id=FilteredRelation('productlikedislike',
condition=Q(productlikedislike__product_liked_by_id=2))).values_list('name',
'photo','productlikedislike')
but getting the same sql query no extra and condition. I am using Django 2.1.5

I got the answer by adding 'productlikedislike_product_liked_by_id' to the values_list(...) that I am using along with FilteredRelation.
So the final query is:
x=Product.objects.filter(Q(photo__cover_photo_flag="yes")|Q(photo__file=None)).annotate(
productlikedislike_product_liked_by_id=FilteredRelation('productlikedislike',condition=Q(pr
oductlikedislike__product_liked_by_id=2))).values_list('name','photo','productlikedislike_p
roduct_liked_by_id')
I printed it it is giving me this resul which I wanted to get:
SELECT "olx_product"."name", "olx_photo"."id",
productlikedislike_product_liked_by_id."id" FROM "olx_product" LEFT OUTER JOIN
"olx_photo" ON ("olx_product"."id" = "olx_photo"."reference_id_id") LEFT OUTER JOIN
"olx_productlikedislike" productlikedislike_product_liked_by_id ON ("olx_product"."id" =
productlikedislike_product_liked_by_id."product_id_id" AND
(productlikedislike_product_liked_by_id."product_liked_by_id_id" = 2)) WHERE
("olx_photo"."cover_photo_flag" = yes OR "olx_photo"."file" IS NULL) ORDER BY
"olx_product"."created" DESC

Related

Doctrine dql with left join using the same table

I am trying to transform the following query to dql:
SELECT cm.*
FROM conversation__conversation cc
INNER JOIN conversation__message cm
ON cm.conversation_id = cc.id
INNER JOIN vehicle__vehicle vv
ON vv.id = cc.vehicle_id
WHERE (cc.driver_id = 25 OR vv.owner_id = 25)
AND cm.id in (SELECT m1.id
FROM conversation__message m1
LEFT JOIN conversation__message m2
ON m1.conversation_id = m2.conversation_id AND m1.id < m2.id
WHERE m2.id IS NULL)
ORDER BY cm.created_at DESC;
I see 2 main difficulties in this query. The first one is that you have a subselect, but I already check how to do it in dql but the really difficult part is to make a left join using the same table. I cannot make it work... anyone knows how to do it?

How to count distinct query in Rails 4 with Postgresql?

I have this ActiveRecord query:
Stock.select('DISTINCT ON (stocks.part_number)*').joins(:part, :manufacturer)
.includes(:manufacturer, :part).order(:part_number).with_cat(category).
where(manufacturers: {abbr: ['manufacturer1', 'manufacturer2']})
with_cat is a scope:
scope :with_cat, -> (category) { where(parts: {category_id: category}) }
Now the reason I am using Distinct on is because every manufacturer can have the same part as another, hence duplicates. I do not want duplicates. The above gets the job done. Except when I add count to it I get an error.
PG::SyntaxError: ERROR: syntax error at or near "ON"
LINE 1: SELECT COUNT(DISTINCT ON (stocks.part_number)*) FROM "stocks...
^
: SELECT COUNT(DISTINCT ON (stocks.part_number)*) FROM "stocks"
INNER JOIN "parts" ON "parts"."id" = "stocks"."part_id"
INNER JOIN "manufacturers" ON "manufacturers"."id" = "stocks"."manufacturer_id"
WHERE "parts"."category_id" = 17 AND "manufacturers"."abbr" IN ('manufacturer1', 'manufacturer2')
Not really sure how to add a count to the query without causing that error. I'm not familiar with Distinct on either. Any explanation as to why this is happening would be great!
Does it fix the query if you use the count ahead of distinct? Got the idea per this postgres documentation.
Stock.select('count(distinct part_number)')...

SQL Update From Where Query

I have 2 tables with information in them. I need to update the SelfServiceUserName column in table A_CLIENT with the value from the SubstVarValue column of the A_DEV_SUBSTVAR_VALUE table when the ClientUID and DeviceID match and the SubstVarName from the A_DEV_SUBSTVAR_VALUE table = samaccount name. Here is the query I've tried to run but I keep getting errors:
UPDATE A_CLIENT
SET SelfServiceUserName = (SELECT SubstVarValue
FROM A_DEV_SUBSTVAR_VALUE
WHERE A_DEV_SUBSTVAR_VALUE.SubstVarName = 'samaccountname')
WHERE A_CLIENT.ClientUID = A_DEV_SUBSTVAR_VALUE.DeviceID
I always write a join between the two tables first to get the rows I want side by side and make sure I have the JOIN clause correct.
SELECT p.ProductID, p.ProductName, p.Price AS OldPrice, n.Price as NewPrice
FROM Products as p
JOIN NewPrices as n on p.ProductID = n.ProductID
Once I have done that it's easy to change it into an update statement by replacing the SELECT clause with an UPDATE and SET:
UPDATE p
SET Price = n.Price
FROM Products as p
JOIN NewPrices as n on p.ProductID = n.ProductID
Note you don't alias the Price on the left side of the SET clause, because it is necessarily from the p (Product) table, so there is no ambiguity. You must still alias the Price on the right of the equals because it could be the field coming from either the p (Product) or n (NewPrice) table.
You could also use a CTE (Common Table Expression) if your SQL engine supports it:
WITH x AS (
SELECT p.ProductID, p.ProductName, p.Price AS OldPrice, n.Price as NewPrice
FROM Products as p
JOIN NewPrices as n on p.ProductID = n.ProductID
)
UPDATE x set OldPrice = NewPrice
Try something like
update a_client c
inner join a_dev_substvar_value d on
c.clientuid = d.deviceid
set
c.selfserviceusername = d.substvarvalue
where
d.substvarname = 'samaccountname';
Note, you should try avoid writing select statements in your were clause because it is run for ever row returned. This can be a big performance hit.
That should work.

Update a table by using multiple joins

I am using Java DB (Java DB is Oracle's supported version of Apache Derby and contains the same binaries as Apache Derby. source: http://www.oracle.com/technetwork/java/javadb/overview/faqs-jsp-156714.html#1q2).
I am trying to update a column in one table, however I need to join that table with 2 other tables within the same database to get accurate results (not my design, nor my choice).
Below are my three tables, ADSID is a key linking Vehicles and Customers and ADDRESS and ZIP in Salesresp are used to link it to Customers. (Other fields left out for the sake of brevity.)
Salesresp(address, zip, prevsale)
Customers(adsid, address, zipcode)
Vehicles(adsid, selldate)
The goal is to find customers in the SalesResp table that have previously purchased a vehicle before the given date. They are identified by address and adsid in Customers and Vechiles respectively.
I have seen updates to a column with a single join and in fact asked a question about one of my own update/joins here (UPDATE with INNER JOIN). But now I need to take it that one step further and use both tables to get all the information.
I can get a multi-JOIN SELECT statement to work:
SELECT * FROM salesresp
INNER JOIN customers ON (SALESRESP.ZIP = customers.ZIPCODE) AND
(SALESRESP.ADDRESS = customers.ADDRESS)
INNER JOIN vehicles ON (Vehicles.ADSId =Customers.ADSId )
WHERE (VEHICLES.SELLDATE<'2013-09-24');
However I cannot get a multi-JOIN UPDATE statement to work.
I have attempted to try the update like this:
UPDATE salesresp SET PREVSALE = (SELECT SALESRESP.address FROM SALESRESP
WHERE SALESRESP.address IN (SELECT customers.address FROM customers
WHERE customers.adsid IN (SELECT vehicles.adsid FROM vehicles
WHERE vehicles.SELLDATE < '2013-09-24')));
And I am given this error: "Error code 30000, SQL state 21000: Scalar subquery is only allowed to return a single row".
But if I change that first "=" to a "IN" it gives me a syntax error for having encountered "IN" (Error code 30000, SQL state 42X01).
I also attempted to do more blatant inner joins, but upon attempting to execute this code I got the the same error as above: "Error code 30000, SQL state 42X01" with it complaining about my use of the "FROM" keyword.
update salesresp set prevsale = vehicles.selldate
from salesresp sr
inner join vehicles v
on sr.prevsale = v.selldate
inner join customers c
on v.adsid = c.adsid
where v.selldate < '2013-09-24';
And in a different configuration:
update salesresp
inner join customer on salesresp.address = customer.address
inner join vehicles on customer.adsid = vehicles.ADSID
set salesresp.SELLDATE = vehicles.selldate where vehicles.selldate < '2013-09-24';
Where it finds the "INNER" distasteful: Error code 30000, SQL state 42X01: Syntax error: Encountered "inner" at line 3, column 1.
What do I need to do to get this multi-join update query to work? Or is it simply not possible with this database?
Any advice is appreciated.
If I were you I would:
1) Turn off autocommit (if you haven't already)
2) Craft a select/join which returns a set of columns that identifies the record you want to update E.g. select c1, c2, ... from A join B join C... WHERE ...
3) Issue the update. E.g. update salesrep SET CX = cx where C1 = c1 AND C2 = c2 AND...
(Having an index on C1, C2, ... will boost performance)
4) Commit.
That way you don't have worry about mixing the update and the join, and doing it within a txn ensures that nothing can change the result of the join before your update goes through.

Django: RawQuerySet problem with passing multiple params

I've used answer from this question:
Django: making raw SQL query, passing multiple/repeated params?
but have some problems.
I have params:
params = {'film_id_string': 'core_film.parent_id', 'tags_params': 'comedy', 'order_by': 'core_film.title', 'content_type': '18', 'language_code': 'en'}
for SQL query:
query = 'SELECT DISTINCT "core_object".*, "core_film".* FROM "core_film" INNER JOIN "core_object" ON ("core_film"."parent_id" = "core_object"."id") LEFT OUTER JOIN "core_objectlocalized" ON ("core_objectlocalized"."parent_id" = %(film_id_string)s) LEFT OUTER JOIN "tagging_taggeditem" ON ("tagging_taggeditem"."object_id" = "core_objectlocalized"."id") LEFT OUTER JOIN "tagging_tag" ON ("tagging_tag"."id" = "tagging_taggeditem"."tag_id") WHERE "tagging_tag"."name" IN (%(tags_params)s) AND "core_objectlocalized"."LANG"=%(language_code)s AND content_type_id=%(content_type)s ORDER BY %(order_by)s'
When I tried to use RawQuerySet
films = Film.objects.raw(query, params)
I get:
SELECT DISTINCT "core_object".*, "core_film".*
FROM "core_film"
INNER JOIN "core_object" ON ("core_film"."parent_id" = "core_object"."id")
LEFT OUTER JOIN "core_objectlocalized" ON ("core_objectlocalized"."parent_id" = E\'core_film.parent_id\')
LEFT OUTER JOIN "tagging_taggeditem" ON ("tagging_taggeditem"."object_id" = "core_objectlocalized"."id")
LEFT OUTER JOIN "tagging_tag" ON ("tagging_tag"."id" = "tagging_taggeditem"."tag_id")
WHERE "tagging_tag"."name" IN (E\'comedy\')
AND "core_objectlocalized"."LANG"=E\'en\'
AND content_type_id=E\'18\'
ORDER BY E\'core_film.title\'
Problem is, that every place with 'E\' generate error similar to this:
DatabaseError: invalid input syntax for integer: "core_film.parent_id"
LINE 1: ...calized" ON ("core_objectlocalized"."parent_id" = E'core_fil...
How can I fix this?
Django version 1.2.3.
edit
I can't remove quotes, because I work with string:
result = self.function(result, tag, "core_film.parent_id")
def function(self, objects, tags, film_id_string):
My params for RawQuerySet look like this:
params = {'film_id_string': film_id_string}
When I try to parse this I get:
LEFT OUTER JOIN "core_objectlocalized" ON ("core_objectlocalized"."parent_id" = E\'core_film.parent_id\')
and then I have problems with
DatabaseError: invalid input syntax for integer: "core_film.parent_id"
LINE 1: ...calized" ON ("core_objectlocalized"."parent_id" = E'core_fil...
but, when I use string formatting
LEFT OUTER JOIN "core_objectlocalized" ON ("core_objectlocalized"."parent_id" = %s)' % film_id_string
it works:
LEFT OUTER JOIN "core_objectlocalized" ON ("core_objectlocalized"."parent_id" = core_film.parent_id)
I want to ommit posibility of SQL injection, so basing on Django docs I don't want to pass params with string formatting.
What can I else do?
Django prevents SQL interjection by escaping parameters. This is an SQL statement, therefore the fact that it does not work is a good thing - Django is doing it's job. Unless the users of the system will be setting the value for "film_id_string" what you did to get it to work should be ok. If not, then you would have to still used the "...%s)' % film_id_string..." method but create your own custom filter to validate that it is one of the correct allowed values.