I am generating a query with sql alchemy part by part. I have this object that is working very well for a query with only one join:
**I have an ORM model, but I cannot use primary keys setted because are not real.
q = select( self.selectObj._select
).select_from(
self.joinObj._join
).where(
and_(*self.whereObj._where)
).group_by(
*self.selectObj._groupby
).order_by(
self.selectObj._orderby
).limit(
self.selectObj._limit
).having(
self.selectObj._having
)
I have this method for generate the joins:
def get_joins(self, first, leftTable, rightTable, leftTableColumn, rightTableColumn, outer):
if first:
self._join = join(leftTable, rightTable, leftTableColumn == rightTableColumn, full=outer)
first = False
else:
self._join = self._join + join(leftTable, rightTable, leftTableColumn == rightTableColumn, full=outer)
I donĀ“t know, how can I generate, concatenate, get, etc two or more joins for use it in the select_from clause. Any idea?
Thanks a lot in advance :)
The final result should be like this in the from:
SELECT a.dev, b.asha, c.unk
FROM a
FULL OUTER JOIN b ON a.dev = b.devicb
FULL OUTER JOIN c ON a.dev = c.devicc
WHERE
a.cust = 'SNTC' AND
b.cust = 'SNTC' AND
c.cust = 'SNTC' AND
a.invent = '10' AND
b.invent = '10' AND
c.invent = '10'
I solved in this way, just invoquing .join in the previous join but only using right table. self._join.join(rightTable,...)
Complete solution for the method:
def get_joins(self, first, leftTable, rightTable, leftTableColumn, rightTableColumn, outer):
if first:
self._join = join(leftTable, rightTable, leftTableColumn == rightTableColumn, full=outer)
first = False
else:
self._join = self._join.join(rightTable, leftTableColumn == rightTableColumn, full=outer)
Related
I'd like to do a and clause with two lists of multiple or clauses from the same table.
The problem with the following code is, that the query result is empty. If I just select 'indices' or 'brokers', the result is fine.
...
query = query.join(StockGroupTicker, on=(Ticker.id == StockGroupTicker.ticker))
# indices
if "indices" in filter:
where_indices = []
for f in filter["indices"]:
where_indices.append(StockGroupTicker.stock_index == int(f))
if len(where_indices):
query = query.where(peewee.reduce(peewee.operator.or_, where_indices))
# broker
if "brokers" in filter:
where_broker = []
for f in filter["brokers"]:
where_broker.append(StockGroupTicker.stock_index == int(f))
if len(where_broker):
query = query.where(peewee.reduce(peewee.operator.or_, where_broker))
return query.distinct()
SQL Querie (update)
# index and brocker
SELECT
DISTINCT `t1`.`id`,
`t1`.`symbol`,
`t1`.`type`,
`t1`.`name`,
`t1`.`sector`,
`t1`.`region`,
`t1`.`primary_exchange`,
`t1`.`currency`,
`t1`.`score`,
`t1`.`last_price`,
`t1`.`last_price_date`,
`t1`.`last_price_check`,
`t1`.`last_stock_split`,
`t1`.`next_earning`,
`t1`.`last_earnings_update`,
`t1`.`disused`,
`t1`.`source`,
`t1`.`source_intraday`,
`t1`.`created`,
`t1`.`modified`,
`t2`.`invest_score` AS `invest_score`
FROM
`ticker` AS `t1`
INNER JOIN `tickerstats` AS `t2` ON
(`t1`.`id` = `t2`.`ticker_id`)
INNER JOIN `stockgroupticker` AS `t3` ON
(`t1`.`id` = `t3`.`ticker_id`)
WHERE
(((((`t1`.`disused` IS NULL)
OR (`t1`.`disused` = 0))
AND (`t2`.`volume_mean_5` > 10000.0))
AND (`t3`.`stock_index_id` = 1))
AND (`t3`.`stock_index_id` = 10)
)
Thanks to #coleifer, the peewee solution is quite simple. I had to use an alias.
if "indices" in filter and filter["indices"]:
query = query.join(
StockGroupTicker, peewee.JOIN.INNER, on=(Ticker.id == StockGroupTicker.ticker)
)
where_indices = []
for f in filter["indices"]:
where_indices.append(StockGroupTicker.stock_index == int(f))
if len(where_indices):
query = query.where(peewee.reduce(peewee.operator.or_, where_indices))
if "brokers" in filter and filter["brokers"]:
BrokerGroupTicker = StockGroupTicker.alias()
query = query.join(
BrokerGroupTicker, peewee.JOIN.INNER, on=(Ticker.id == BrokerGroupTicker.ticker)
)
where_broker = []
for f in filter["brokers"]:
where_broker.append(BrokerGroupTicker.stock_index == int(f))
if len(where_broker):
query = query.where(peewee.reduce(peewee.operator.or_, where_broker))
return query.distinct()
I'm trying to make a left outer join relation between two tables using joinedload but it doesn't seems to have the same behavior as using outerjoin method.
Here is an example using outerjoin:
stmt = select(ServerFarm)
stmt = stmt.outerjoin(
Server,
(ServerFarm.name == Server.server_farm_id) & (Server.deleted == False)
)
stmt = stmt.filter(ServerFarm.name == name)
print(stmt)
# SELECT ... FROM server_farm
# LEFT JOIN server ON server_farm.name = server.server_farm_id and server.deleted = False
# WHERE server_farm.name = :name
So when I'm using joinedload this is what happens:
stmt = select(ServerFarm)
stmt = stmt.options(
joinedload(
ServerFarm.servers,
(ServerFarm.name == Server.server_farm_id) & (Server.deleted == False)
)
)
stmt = stmt.filter(ServerFarm.name == name)
# SELECT ... FROM server_farm
# LEFT JOIN server ON server_farm.name = server.server_farm_id
# WHERE server_farm.name = :name
On this case, it just ignores the (Server.deleted == False) option. What am I doing wrong? Is there a way to add a "custom" filter on a left outer join using joinedload? How?
Any ideas for how I could do a nested join using SQLAlchemy? Here is the raw query I am trying to recreate.
SELECT "tblLinkDivisions"."DivisionCoLinkID", 5 AS Score, "tblCompanies"."CompanyID"
FROM "tblS_AppliedStrategy"
INNER JOIN
(
(
"tblLinkIndustry" INNER JOIN "tblLinkDivisions" ON "tblLinkIndustry"."IndustryCoLinkID" = "tblLinkDivisions"."IndustryCoLinkID"
)
INNER JOIN "tblLinkAppliedStrategy"
ON "tblLinkDivisions"."DivisionCoLinkID" = "tblLinkAppliedStrategy"."DivisionCoLinkID"
)
ON "tblS_AppliedStrategy"."AppStrategyCode" = "tblLinkAppliedStrategy"."AppStrategyCode"
INNER JOIN "tblCompanies" ON ("tblCompanies"."CompanyID" = "tblLinkIndustry"."CompanyID" AND "tblCompanies"."CompanyID" != %s)
WHERE "tblS_AppliedStrategy"."AppStrategyCode" IN %s
I have tried a few different solutions with this being the closest outcome:
companies = (
session.query(tblLinkDivisions.DivisionCoLinkID, tblCompanies.CompanyID)
.select_from(tblS_AppliedStrategy)
.join(tblLinkIndustry, tblLinkDivisions.IndustryCoLinkID == tblLinkIndustry.IndustryCoLinkID)
.join(tblLinkAppliedStrategy, tblLinkDivisions.DivisionCoLinkID == tblLinkAppliedStrategy.DivisionCoLinkID)
.join(tblLinkAppliedStrategy, tblS_AppliedStrategy.AppStrategyCode == tblLinkAppliedStrategy.AppStrategyCode)
.join(tblCompanies, and_(tblCompanies.CompanyID == tblLinkIndustry.CompanyID, tblCompanies.CompanyID != company_id))
.filter(tblS_AppliedStrategy.AppStrategyCode.in_(strategy))
.all()
)
Any help or suggestions would be greatly appreciated!
I have a table that have enemy_one, fight_id and enemy_two.
The thing is, sometimes enemy_two becomes enemy_one and vice versa.
I can do:
session.query(Fight.fight_id).filter(Fight.enemy_one=='Jack', Fight.enemy_two=='Fat Chinese').all()
then:
session.query(Fight.fight_id).filter(Fight.enemy_one=='Fat Chinese', Fight.enemy_two=='Jack').all()
And this way I get all the fights, but there's a way, to bind this two query's together?
With the in_ clause:
def get_fights(enemy_one, enemy_two):
return (
session
.query(Fight)
.filter(Fight.enemy_one.in_([enemy_one, enemy_two]))
.filter(Fight.enemy_two.in_([enemy_one, enemy_two]))
.filter(Fight.enemy_one != Fight_enemy_two)
)
With the or_ clause:
def get_fights(enemy_one, enemy_two):
return (
session
.query(Fight)
.filter(or_(
and_(Fight.enemy_one == enemy_one, Fight.enemy_two == enemy_two),
and_(Fight.enemy_one == enemy_two, Fight.enemy_two == enemy_one),
))
)
Feel free to use sqlalchemy's function or_() with the filter operator in_ like this:
from sqlalchemy import or_
enemies = ['Fat Chinese', 'Jack']
session.query(Fight.fight_id).filter(
or_(
Fight.enemy_one.in_(enemies),
Fight.enemy_two.in_(enemies)
)).all()
I want to perform this SQL query using Sqlalchemy (with model Evaluation):
select e1.user, sum(e1.points) as s from
(select e1.*
from evaluations e1 left outer join evaluations e2
on (e1.user = e2.user and e1.module = e2.module and e1.time < e2.time)
where e2.user is null and e1.module in (__another subquery__))
group by e1.user order by s limit 5
I don't know how to perform left outer join (especialy the renaming and referencing of renamed comlumns). Could you help me?
# sample sub-query for testing
_another_query = session.query(Evaluation.module).filter(Evaluation.module > 3)
# define aliases
E1 = aliased(Evaluation, name="e1")
E2 = aliased(Evaluation, name="e2")
# inner query
sq = (
session
# .query(E1)
# select columns explicitely to control labels
.query(E1.user.label("user"), E1.points.label("points"))
.outerjoin(E2, and_(
E1.user == E2.user,
E1.module == E2.module,
E1.time < E2.time,
))
.filter(E2.user == None)
.filter(E1.module.in_(_another_query))
)
sq = sq.subquery(name="sq")
# now lets group by
q = (
session
.query(sq.c.user, func.sum(sq.c.points))
.group_by(sq.c.user)
.order_by(func.sum(sq.c.points))
.limit(5)
)