Here is SQL that works as expected:
SELECT
m.*,
d.*
FROM (
SELECT
person_id,
service_id,
person_id_internal,
meters_readings, -- two-dimensional array
meters_readings [generate_subscripts(meters_readings, 1)] [1] AS meter_id,
meters_readings [generate_subscripts(meters_readings, 1)] [2] AS
organization_reading,
date
FROM
databases
) d LEFT OUTER JOIN LATERAL (
SELECT DISTINCT ON (service_id, person_id_internal, meter_id)
user_id,
reading
FROM meter_readings
WHERE
person_id = d.person_id AND
service_id = d.service_id AND
meter_id = d.meter_id AND
commit_date > d.date AND
rollback_date IS NULL AND
reading IS NOT NULL
ORDER BY
service_id,
person_id_internal,
meter_id,
commit_date DESC,
commit_time DESC
) m ON TRUE
WHERE
d.person_id = 2099000301470;
And that is SA query that also works :) I managed to write it ))
def get_person_meters_q(dbsession, person_id):
database = dbsession.query(
Database.person_id,
Database.service_id,
Database.person_id_internal,
Database.date,
(
type_coerce(
Database.meters_readings[
func.generate_subscripts(Database.meters_readings, 1)
],
type_=ARRAY(Text)
)[1]
).label('meter_id'),
(
type_coerce(
Database.meters_readings[
func.generate_subscripts(Database.meters_readings, 1)
],
type_=ARRAY(Text)
)[2]
).label('organization_reading')
).subquery()
meter_readings = dbsession.query(
MeterReading.user_id,
MeterReading.reading
). \
distinct(
MeterReading.service_id,
MeterReading.person_id_internal,
MeterReading.meter_id). \
filter(
and_(
MeterReading.person_id == database.c.person_id,
MeterReading.service_id == database.c.service_id,
MeterReading.meter_id == database.c.meter_id,
MeterReading.commit_date > database.c.date,
MeterReading.rollback_date == None,
MeterReading.reading != None
)
). \
order_by(
MeterReading.service_id,
MeterReading.person_id_internal,
MeterReading.meter_id,
MeterReading.commit_date.desc(),
MeterReading.commit_time.desc()
).subquery().lateral()
q = dbsession.query(
meter_readings,
database
). \
select_from(
database.outerjoin(meter_readings, true())
).filter(database.c.person_id == person_id)
return q
The problem with extra "database" table name in select was because I use
filter(Database.person_id == person_id)
but not filter(database.c.person_id == person_id)
About LATERAL
https://www.postgresql.org/docs/current/static/sql-select.html
The LATERAL key word can precede a sub-SELECT FROM item.
This allows the sub-SELECT to *refer to columns of FROM items **that appear
before it* in the FROM list.
(Without LATERAL, each sub-SELECT is evaluated independently and so cannot
cross-reference any other FROM item.)
So I refer columns that are in database query (first) from meter_readings query
(second select)
Without LATERAL I get:
ERROR: invalid reference to FROM-clause entry for table "d"
Hint: There is an entry for table "d", but it cannot be referenced from this
part of the query.
And that is SQL query result:
\N \N 2099000153759 75 952160 {{952160,1140,0}} 952160
1140 2017-11-30
\N \N 2099000153759 2 27852 {{219935,14768,0}} 219935
14768 2017-11-30
\N \N 2099000153759 4 206688 {{468805,57,0},{589164,73,0}}
468805 57 2017-11-30
\N \N 2099000153759 4 206688 {{468805,57,0},{589164,73,0}}
589164 73 2017-11-30
--
SQLAlchemy -
The Python SQL Toolkit and Object Relational Mapper
http://www.sqlalchemy.org/
To post example code, please provide an MCVE: Minimal, Complete, and Verifiable
Example. See http://stackoverflow.com/help/mcve for a full description.
---
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 https://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.