Hi,
Using SQLAlchemy 0.9.8 and Postgres 9.3.
I'm in the process of re-writing my raw SQL using SQLAlchemy ORM but having
some trouble with my CTEs.
## Raw SQL
WITH suitability_positive AS (
SELECT
occupation_id,
sum(match) AS match
FROM
suitability_match
INNER JOIN user_activity ON
user_activity.activity_id =
suitability_match.activity_id
AND
user_activity.preference = suitability_match.preference
WHERE
user_id = :user_id
AND
match > 0
GROUP BY
occupation_id
),
suitability_negative AS (
SELECT
occupation_id,
sum(match) AS match
FROM
suitability_match
INNER JOIN user_activity ON
user_activity.activity_id =
suitability_match.activity_id
AND
user_activity.preference = suitability_match.preference
WHERE
user_id = :user_id
AND
match < 0
GROUP BY
occupation_id
),
combined AS (
SELECT * FROM positive
UNION
SELECT * FROM negative
)
SELECT
occupation_id,
sum(match) AS suitability_match
FROM
combined
GROUP BY
occupation_id;
So this might not be very optimized, but I have some related queries that
are much larger and using CTEs is the only way I can stay sane. When
re-writing using the ORM, I'm not sure which subqueries I need to be
aliasing and than how to use `UNION` with them. This was my attempt:
## SQLAlchemy
positive = DBSession.query(
SuitabilityMatch.occupation_id,
func.sum(SuitabilityMatch.match).label('match')
)\
.join(UserActivity,
and_(
UserActivity.activity_id == SuitabilityMatch.activity_id,
UserActivity.preference == SuitabilityMatch.preference
)
)\
.filter(
UserActivity.user_id == self.id,
SuitabilityMatch.match > 0
)\
.group_by(
SuitabilityMatch.occupation_id
)\
.cte('positive')
negative = DBSession.query(
SuitabilityMatch.occupation_id,
func.sum(SuitabilityMatch.match).label('match')
)\
.join(UserActivity,
and_(
UserActivity.activity_id == SuitabilityMatch.activity_id,
UserActivity.preference == SuitabilityMatch.preference
)
)\
.filter(
UserActivity.user_id == self.id,
SuitabilityMatch.match < 0
)\
.group_by(
SuitabilityMatch.occupation_id
)\
.cte('negative')
combined = positive.union(negative).cte('combined')
query = DBSession.query(
combined.occupation_id,
func.sum(combined.match).label('suitability_match')
)\
.group_by(
combined.occupation_id
)\
.all()
The `combined` expression yields AttributeError: 'CTE' object has no
attribute 'cte'
So if I change
combined = positive.union(negative).cte('combined')
to
combined = positive.union(negative)
and
query = DBSession.query(
combined.occupation_id,
func.sum(combined.match).label('suitability_match')
)\
.group_by(
combined.occupation_id
)\
.all()
to
query = DBSession.query(
combined*.c*.occupation_id,
func.sum(combined*.c*.match).label('suitability_match')
)\
.group_by(
combined*.c*.occupation_id
)\
.all()
I get SQL, but it's not the SQL I desire. This is the output (indented to
make it more readable):
WITH negative AS (
SELECT
suitability_match.occupation_id AS occupation_id,
sum(suitability_match.match) AS match
FROM
suitability_match
JOIN user_activity ON
user_activity.activity_id =
suitability_match.activity_id
AND
user_activity.preference = suitability_match.preference
WHERE
user_activity.user_id = %(user_id_2)s
AND
suitability_match.match < %(match_2)s
GROUP BY
suitability_match.occupation_id
),
positive AS (
SELECT
suitability_match.occupation_id AS occupation_id,
sum(suitability_match.match) AS match
FROM
suitability_match
JOIN user_activity ON
user_activity.activity_id =
suitability_match.activity_id
AND
user_activity.preference = suitability_match.preference
WHERE
user_activity.user_id = %(user_id_1)s
AND
suitability_match.match > %(match_1)s
GROUP BY
suitability_match.occupation_id
)
UNION negative
SELECT
positive.occupation_id AS positive_occupation_id,
sum(positive.match) AS suitability_match
FROM
positive
GROUP BY
positive.occupation_id
Everything looks identical to the original, raw SQL except the UNION and
final SELECT statement, where it looks like `combined` is still referencing
`positive`. I've tried different combinations of `.alias()` and
`.subquery()` but I'm really just guessing at this point.
So...
How do I `UNION` the first 2 queries?
How do I make the result of that `UNION` another CTE?
How do I reference the combined CTE in the final `SELECT` statement?
Thanks!
--
You received this message because you are subscribed to the Google Groups
"sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.